home *** CD-ROM | disk | FTP | other *** search
/ Mac-Source 1994 July / Mac-Source_July_1994.iso / C and C++ / Text⁄Files / Suntar 1.3.2 / untar.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-10-31  |  89.2 KB  |  2,989 lines  |  [TEXT/KAHL]

  1. /* Copyright 1988, Gail Zacharias.  All rights reserved.
  2.  * Permission is hereby granted to copy, reproduce, redistribute or
  3.  * otherwise use this software provided there is no monetary profit
  4.  * gained specifically from its use or reproduction, it is not sold,
  5.  * rented, traded or otherwise marketed, and this copyright notice
  6.  * and the software version number is included prominently in any copy
  7.  * made.
  8.  * This was muntar version 1.0.
  9.  *
  10.  */
  11.  
  12. /* the original muntar program was then altered to become part of suntar:
  13. */
  14.  
  15. /*******************************************************************************\
  16.  
  17. tar reading module
  18.  
  19. part of suntar, ©1991-92 Sauro & Gabriele Speranza
  20.  
  21. This program is public domain, feel free to use it or part of it for anything
  22.  
  23. \*******************************************************************************/
  24.  
  25. /*
  26. comments in the text explain which routines were added for suntar by us and
  27. which ones are from muntar, but most of the latter were modified more or less 
  28. heavily by us. In fact, the file is divided into four sections:
  29. a few declarations by Gail Zacharias
  30. a series of routines 100% by Speranza
  31. a series of routines containing also old code by Zacharias but which do new things
  32. a series of old routines by Zacharias: none of them is still in the original
  33.     form, but the calling interface is usually unchanged
  34. */
  35.  
  36. #define USA_CURRVREFN
  37.  
  38.  
  39.  
  40. #include "PB_sync.h"
  41. #include "antiglue.h"
  42. #include "windows.h"
  43. #include "suntar.h"
  44.  
  45. /*#include <FileMgr.h>
  46. #include <OSUtil.h>
  47. #include <HFS.h>*/
  48. #include <string.h>
  49. /* #include <errors.h> */
  50.  
  51. #define ASM
  52.  
  53. #define tarsz(n)    (((n)+511L) & -512L)
  54. #define  macbinsz(n)    (((n)+127L) & -128L)
  55.  
  56. char *strrchr();
  57.  
  58.  
  59. struct binh_type macbinh;
  60. tarh_type tarh;
  61. unsigned char disk_buffer [512];
  62.  
  63. OSType filecreator,filetype;
  64. unsigned char listonly=0;
  65.  
  66. /* alcune routines sue un po' riscritte (ho il sospetto esistano in libreria o nella ROM,
  67. ma non so con che nomi e che parametri, tanto vale riscriversele
  68. */
  69.  
  70.  
  71. StringPtr my_c2pstr(p)    /* had to change the name since TH C 5 has its own
  72.                         define for c2pstr, and a define takes precedence */
  73. register char p[];
  74. {
  75. register short i,len=strlen(p);
  76. for(i=len;i>0;i--)
  77.     p[i]=p[i-1];
  78. p[0]=len;
  79. return (StringPtr) p;
  80. }
  81.  
  82. char * my_p2cstr(p)
  83. register unsigned char p[];
  84. {
  85. register short i,len=p[0];
  86. for(i=0;i<len;i++)
  87.     p[i]=p[i+1];
  88. p[len]='\0';
  89. return p;
  90. }
  91.  
  92. /* main() l'ho tolto di torno...
  93. {
  94. printf(
  95. "This is freeware.  If you paid money for this program, you got ripped off.\n");
  96.   return;
  97. }
  98. */
  99.  
  100. short binary=true; /* se convertire LF-CR o no */
  101. #define UNIXTIME    2082844800L  /* Jan 1, 1970 00:00:00 */
  102.  
  103. #ifndef ASM
  104. /* simple implementation */
  105. void mcopy(dest, src, len)
  106. register char*dest,*src;
  107. register unsigned short len;
  108. {
  109.     while ((short)--len>=0) *dest++ = *src++;
  110. }
  111. #endif
  112.  
  113.  
  114. /******************** start of routines by Speranza ***********************/
  115.  
  116. #ifdef ASM
  117. void mcopy(char * dest,char * src,unsigned short len )
  118.  
  119. /* optimazed implementation, remembering that the 68000 is a 32 bit machine
  120. and may move 4 bytes at a time, at least if they are placed at an even address
  121. (since the compiler places at even addresses the start of all data structures, 
  122. that means almost always)
  123. By Gabriele Speranza, 17 Nov 1991
  124. */
  125.  
  126. {
  127. extern SysEnvRec    gMac;
  128. /* #define EXPLOIT_020 */
  129. asm {
  130.     move.l    dest,a0
  131.     move.l    src,a1
  132.     move.w    len,d1
  133.         /* 
  134.         #ifndef EXPLOIT_020 / * suntar uses mcopy only for small * /
  135.             / * copies, and those which are not aligned are rarely big, * /
  136.             / * probably it's not worth of it, that symbol is NOT defined * /
  137.         if(len>=10 && !((((long)dest)^((long)src))&1) ){
  138.             / *    if the transfer is long enough and the pointers have the same parity * /
  139.         #else
  140.         if(len>=10 && ( gMac.processor>=env68020 || !((((long)dest)^((long)src))&1) ) ){
  141.             / * the 68020 and later CPUs do not require same parity * /
  142.         #endif
  143.         */
  144.     cmp.w    #10,d1
  145.     blt.s    @inloop
  146.     move.l    a0,d0
  147. #ifdef EXPLOIT_020
  148.     cmp.w    #env68020,gMac.processor
  149.     bge        @ok_to_movelong
  150. #endif
  151.     move.l    a1,d2
  152.     eor.l    d0,d2
  153.     lsr.l    #1,d2
  154.     bcs.s    @inloop
  155. ok_to_movelong:
  156.  
  157.         /* if(((long)dest)&1){
  158.                 *dest++ = *src++;    / * both odd=>move one byte to get both even * /
  159.                 len--;
  160.                 }
  161.         */
  162.     lsr.l    #1,d0
  163.     bcc.s    @l1
  164.     move.b    (a1)+,(a0)+
  165.     subq.w    #1,d1
  166.     addq.l    #1,d0    /* se il LSB era 1, aggiungere 1 provoca carry sul bit 1 
  167.                     -- bit 0 was shifted out, and was 1: adding 1 to bit 0 will cause
  168.                     a carry to bit 1, but bit 1 was shifted to bit 0...*/
  169.         /* if(((long)dest)&2){
  170.             / * now I have two even addresses, and that's good. But a destination 
  171.             at an address multiple of 4 better exploits a 32 bit bus.
  172.             Obviously, the same is for the source, but in 50% of cases aligning one
  173.             aligns the other too, and the cache works better when reading, hence a 
  174.             misalignment on reading is less bad then on writing.
  175.             Really, I've an LC where the bus is 16 bit wide, and the cache is used
  176.             only for instructions, so this trick is not fully exploited on my machine! * /
  177.             *((short*)dest)++ = *((short*)src)++;
  178.             len -= 2;
  179.             }
  180.         */
  181. l1:    lsr.l    #1,d0
  182.     bcc.s    @l2
  183.     move.w    (a1)+,(a0)+
  184.     subq.w    #2,d1
  185.         /*
  186.             for(temp=len/4;temp;temp--)
  187.                 *((long*)dest)++ = *((long*)src)++;
  188.             len %=4;
  189.         */
  190. l2:    move.w    d1,d0
  191.     lsr.w    #2,d0
  192.     subq.w    #1,d0
  193. loop1:move.l (a1)+,(a0)+
  194.     dbra d0,@loop1
  195.     and.w    #3,d1    /* up to 3 further bytes may have to be moved ... */
  196.         /*
  197.             }    / * end if: now move byte-wise anything is remaining, 
  198.                 that is all the job if couldn't move long-wise * /
  199.             while (len-- >0) *dest++ = *src++;
  200.         */
  201.     bra.s    @inloop
  202. loop2:    move.b (a1)+,(a0)+
  203. inloop:    dbra d1,@loop2
  204.     }
  205. }
  206. #endif
  207.  
  208. #define dp printf
  209.  
  210.  
  211. Boolean chiedi_su_questo(short,sector_t,char*,Str255,Str255,Str255);
  212. OsErr verifica_nome(short,sector_t *);
  213. short isMacBin2(unsigned char*);
  214. void make_badname(char*,char*);
  215. Boolean too_long(char *);
  216. Boolean is_gif_file(long);
  217. short gestisci_nome_doppio(char *,char*,FileParam *,Boolean);
  218. static void skip_macbinII(short);
  219. void cancella_file_aperto(short);
  220. void print_containing(void);
  221. Boolean is_bad_name(char *);
  222.  
  223.  
  224. jmp_buf main_loop;
  225. long file_date;
  226. unsigned char mac_file_name[120];    /* deve poter contenere un path completo...*/
  227. short openfile_vrefnum;
  228. long openfile_dirID;
  229.  
  230. short more_in_bytes;    /* I don't remember the number of bytes currently in the 
  231.                     buffer, but more_in_bytes = 512-number of bytes = free space */
  232. sector_t sect_n;
  233. ParamBlockRec pb;    /* è diventata una variabile globale per poter chiudere il file in
  234.                     caso di errore; proprio per questo però ha senso che anche il nome
  235.                     del file, puntato da un campo del record, sia globale */
  236. #define ioDirID ioFlNum
  237. short floppy_n;
  238. Boolean bar_archive;
  239. static Boolean notTrueMacBinary,MacBinaryII;
  240. static unsigned short mbIIsec_head_len;
  241. Boolean all_listonly;
  242. Boolean devo_chiudere_out=false;
  243. /* gruppetto di variabili usate per la verifica di un header 'M' del GNU tar, ma
  244. anche per altri scopi, sia in lettura sia in scrittura */
  245. Boolean ultimo_header_valido;
  246. Boolean ultimo_disco_espulso;    /* il disco contenente quell'ultimo header è stato
  247.                                 espulso ? */
  248. Boolean hasVheader;
  249. char ultimo_header[184];        /* usata anche per altri scopi, viene SEMPRE aggiornata
  250.                                 coi primi 184 bytes dell'ultimo header, tar o bar, che
  251.                                 si è letto o scritto
  252.                                 -- I always copy here the first 184 bytes of any 
  253.                                 tar or bar file header which is being read (here) or
  254.                                 written (in tar.c)
  255.                                 */
  256. long last_offset;        /* solo per GNU tar */
  257. sector_t next_header_for_AIX;    /* only for tar archives, useful only for AIX:
  258.                             -1 if next header is on same disk, otherwise number
  259.                             of sector in next disk */
  260. sector_t avail_sectors_for_file;    /* = sectors_on_floppy - sect_n successivo di quando ho 
  261.                                     caricato ultimo_header
  262.                             -- = sectors_on_floppy - the sector following the header
  263.                             */
  264. static char UNEXP[]="\nUnexpected end of file\n";
  265.  
  266. /* titoli italiani dei bottoni dei dialoghi modali 
  267. -- italian titles of the buttons */
  268. char *titoli[]={"\pSì","\pNo"};
  269. char *titoli_full[]= {"\pContinua qui","\pContinua altrove","\pNon salvare"};
  270. char s_spazi[]="              ";
  271.  
  272. #define FLUSH_MIN_SIZE 10240
  273.  
  274. /****************************/
  275.  
  276. /* do some buffering towards the hard disk. If I write in relatively small
  277. pieces (e.g. 5Kbytes) the Mac freezes for a few seconds from time to time,
  278. (maybe flushing the disk buffers?) yielding big total times. With 10K
  279. everything works regularly and about two times faster (three times faster than
  280. suntar 1.2.2, thanks to some other improvements).
  281. */
  282.  
  283. static char*hd_buffer;
  284. static short bytes_in_hd_buffer;
  285.  
  286. unsigned short hd_buffer_size;
  287.  
  288. void init_hd_buffering()
  289. {
  290. ResrvMem ((Size)hd_buffer_size);
  291. hd_buffer=NewPtr((Size) hd_buffer_size);
  292. check_allocated(hd_buffer);
  293. }
  294.  
  295. #define reinit_hd_buffering() bytes_in_hd_buffer=0
  296.  
  297. OSErr flush_hd_buffer(void);
  298. static OSErr flush_hd_buffer()
  299. {
  300. OSErr err;
  301. if(!bytes_in_hd_buffer) return noErr;
  302.  
  303. pb.ioParam.ioPosMode = fsAtMark;
  304. pb.ioParam.ioPosOffset = 0;
  305. pb.ioParam.ioBuffer = hd_buffer;
  306. pb.ioParam.ioReqCount=bytes_in_hd_buffer;
  307. bytes_in_hd_buffer=0;
  308. if( (err=PBWriteSync(&pb)) || pb.ioParam.ioResult) return pb.ioParam.ioResult;
  309.  
  310. if(pb.ioParam.ioReqCount != pb.ioParam.ioActCount) return ioErr;
  311. return noErr;
  312. }
  313.  
  314. OSErr write_hd(char*,short);
  315. static OSErr write_hd(buffer,size)
  316. char*buffer;
  317. short size;
  318. {
  319. OSErr i;
  320. if(bytes_in_hd_buffer>hd_buffer_size-size)
  321.     if((i=flush_hd_buffer())) return i;
  322. mcopy(hd_buffer+bytes_in_hd_buffer,buffer,size);
  323. if((bytes_in_hd_buffer+=size)==hd_buffer_size)
  324.     return flush_hd_buffer();
  325. return noErr;
  326. }
  327.  
  328. /******************************/
  329.  
  330. short readblock(buf,nbytes)
  331. /* this routines translates from the sector-based view of the device driver
  332. to the "byte stream" view used by most of the program, by buffering reads
  333. and controlling disk swaps
  334. Never call it asking for more than 512 bytes, the "buffer fill" operation is
  335. performed at most once.
  336. */
  337. register char*buf;
  338. short nbytes;
  339. {
  340. short i;
  341.  
  342. /*printf("readblock(%d)\n",nbytes);*/
  343. if(more_in_bytes<nbytes){
  344.     if(more_in_bytes){
  345.         nbytes-=more_in_bytes;
  346.         mcopy(buf,&disk_buffer[512-more_in_bytes],more_in_bytes);
  347.         buf+=more_in_bytes;
  348.         }
  349.     if(bar_archive)
  350.         bar_check_floppy_swap(0);
  351.     else
  352.         tar_check_floppy_swap(0);
  353.     leggi_settore(sect_n,&disk_buffer);
  354.  /*printf("leggo settore %ld,err=%d\n",(long)sect_n,err_code);*/
  355.      if((i=check_error_and_events())<0) return -1;
  356.      if(i>0){    /* "missing disk" was converted to a pause event, now the disk
  357.                  should be in, but I must repeat the operation */
  358.         leggi_settore(sect_n,&disk_buffer);
  359.          if(check_error()) return err_code;
  360.          }
  361.     more_in_bytes=512;
  362.     sect_n++;
  363.     settori_passati++;
  364.     }
  365. mcopy(buf,&disk_buffer[512-more_in_bytes],nbytes);
  366. more_in_bytes-=nbytes;
  367. return 0;
  368. }
  369.  
  370. void unget_block()
  371. {
  372. /* viene chiamata per l'unget dei primi bytes di un file, quindi
  373. -- used to unget the first bytes of a file: they are still in the buffer, hence:
  374. */
  375. more_in_bytes=512;
  376. }
  377.  
  378. void unget_char()
  379. {
  380. more_in_bytes++;
  381. }
  382.  
  383. /*
  384. attenzione che anche nei moduli dehqx e unpit uso i buffer e more_in_bytes !
  385. -- caution: modifying the above functions, take a look at hqx_end_of_file &
  386. get_hqx_byte & fast_get_hqx_byte in dehqx.c, and fast_get_pit_byte in unpit.c,
  387. which are partially copied from the above and use the same data structures
  388. */
  389.  
  390.  
  391. void end_of_file()
  392. {
  393. /* è chiamata per saltare sopra gli ultimi bytes prima dell' header del file
  394. seguente, quindi non c'è che passare al settore successivo
  395. -- it skips the last bytes of the current sector: next read will read
  396. an header which is aligned at the start of a sector
  397. */
  398. more_in_bytes=0;
  399. }
  400.  
  401. void skip_file(fsize)
  402. /* it increments the sector number: the disk swap routines are designed to 
  403. handled case when the requested sector is not the first sector in next disk */
  404. long fsize;
  405. {
  406. if(fsize<=512)return;    /* il primo settore è già stato letto */
  407. sect_n+= (fsize-1) >>9;
  408. }
  409.  
  410.  
  411. /*************************/
  412.  
  413. void stampa_buffer(sect_n,buffer)
  414. /* utilissima nel debugging
  415. -- it was written for debugging, then it became a permanent part of the program
  416. executing the View sector command
  417. */
  418. sector_t sect_n;
  419. unsigned char *buffer;
  420. {short i,j=0,x;
  421. disable_autoflush(2);
  422. for(i=0;i<512;i++){
  423.     if((x=buffer[i])<16)
  424.         printf("0%x",x);
  425.     else if(x>=' '&&x<127)
  426.         printf(" %c",x);
  427.     else
  428.         printf("%x",x);
  429.     if(j==24){
  430.         put_char('\n');
  431.         j=0;
  432.         }
  433.     else{
  434.         put_char(' ');
  435.         j++;
  436.         }
  437.     }
  438. printf("        end of sector %ld\n",(long)sect_n);
  439. enable_autoflush();
  440. }
  441.  
  442. /***************************/
  443.  
  444. short isASCII(fsize,nLF)
  445. /* decide if the file is ASCII examining the first sector of its data
  446. (which was already read by chkmacbin, or is read and ungetted here)
  447. returns:
  448. 1 it's ASCII
  449. 0 it's not ASCII
  450. -1 the percentage of ASCII bytes is high enough to deserve a 'TEXT' type,
  451.     maybe that file was created on a Mac which gives a meaning to many
  452.     not ASCII chars (e.g. ©), but it's too low to choose to modify the 
  453.     data by automatically converting any LF to CR...
  454. */
  455. long fsize;
  456. short*nLF;
  457. {
  458. register short i,n_non_ASCII;
  459. short nbytes;
  460. register char c;
  461.  
  462. nbytes= fsize>512? 512 : fsize;
  463. if(nbytes==0) return 0;  /* troppo corto per 
  464.     decidere, e se è 0 non ha senso dargli l'icona di testo... */
  465. if(more_in_bytes==0){
  466.     if(readblock(nLF,1)) raise_error();    /* fill the disk_buffer...*/
  467.     unget_block();
  468.     }
  469. *nLF=0;
  470. n_non_ASCII=0;
  471. for(i=nbytes-1;i>=0;i--){
  472.     c=disk_buffer[i];
  473.     if(c>=' ' && c <= 126)
  474.         ;    /* ASCII */
  475.     else if(c==CR || c== '\t' || c=='\f')
  476.         ;
  477.     else if(c==LF)
  478.         (*nLF)++;
  479.     else{
  480.         if(++n_non_ASCII>(14+(512>>5))) break;
  481.         }
  482.     }
  483. if( !n_non_ASCII && (nbytes>=80  || smallFilesAreASCII) ) return 1;
  484. return n_non_ASCII > 14+(nbytes>>5) ? 0 : -1;
  485. }
  486.  
  487. Boolean print_if_string(format,buffer,size)
  488. char*format,*buffer;
  489. short size;
  490. {
  491. /* for error reporting: something coming from a sector containing errors is printed
  492. only if it looks like a string (only ASCII characters, a terminating '\0', no '\n'... */
  493. short i=0;
  494.  
  495. size--;
  496. while(i<size && buffer[i]>=' ' && buffer[i]<127 )
  497.     i++;
  498. if(i==0 || buffer[i]) return false;    /* empty string or end of string not reached */
  499. printf(format,buffer);
  500. return true;
  501. }
  502.  
  503. /***************************/
  504.  
  505. void my_untar()        /* intermediate-level handler of the Extract and List commands */
  506. {
  507. short fine,i;
  508. long lunghezza_file();
  509.  
  510. more_in_bytes=0;
  511. bar_archive=0;
  512. all_listonly=listonly;
  513.  
  514. tar_check_floppy_swap(1);    /* ci sono delle inizializzazioni
  515.     -- obviously I don't swap disks before beginning, but it 
  516.     initializes some variables and checks sector 0
  517.     */
  518.  
  519. do{
  520.  
  521.     leggi_settore(sect_n,&disk_buffer);
  522.     if(err_code==eofErr)
  523.         fine=true;
  524.     else{
  525.          if((i=check_error_and_events())<0) raise_error();
  526.          if(i>0){
  527.             leggi_settore(sect_n,&disk_buffer);
  528.              if(check_error()) raise_error();
  529.              }
  530.         fine=check_all_zero(disk_buffer);
  531.         }
  532.     if(!fine){
  533. /*printf("n_settori=%ld\n",((untar_number(&disk_buffer[124],false)+511)/512) );*/
  534.  
  535.         untar();
  536.         tar_check_floppy_swap(-1);
  537.         }
  538.     }
  539. while(!fine);
  540. if(sect_n==0){
  541.     one_empty_line();
  542.     printf(in_Italia?"Archivio vuoto\n":"No files in the archive\n");
  543.     }
  544. else{
  545.     if(expert_mode)
  546.         print_sector_n(sect_n);
  547.     else
  548.         printf("\n");
  549.     printf(in_Italia?"Fine archivio\n":"End of archive\n");
  550.     }
  551. }
  552. /************** gestione del formato bar *************/
  553. /* bar format handling */
  554.  
  555. void my_unbar()
  556. {
  557. short fine,i;
  558.  
  559. bar_archive=1;
  560. all_listonly=listonly;
  561. more_in_bytes=0;
  562.  
  563. bar_check_floppy_swap(1);
  564.  
  565. do{
  566.     leggi_settore(sect_n,&disk_buffer);
  567.     if(err_code==eofErr)
  568.         fine=true;
  569.     else{
  570.          if((i=check_error_and_events())<0) raise_error();
  571.          if(i>0){
  572.             leggi_settore(sect_n,&disk_buffer);
  573.              if(check_error()) raise_error();
  574.              }
  575.         fine=check_all_zero(disk_buffer);
  576.         }
  577.  
  578.     if(!fine){
  579.         unbar();
  580.         bar_check_floppy_swap(-1);
  581.         }
  582.     }
  583. while(!fine);
  584. if(expert_mode)
  585.     print_sector_n(sect_n);
  586. else
  587.     printf("\n");
  588. printf(in_Italia?"Fine archivio\n":"End of archive\n");
  589. }
  590.  
  591.  
  592. short unbar_checksum(buffer,do_error,exp_check)
  593. register unsigned char *buffer;
  594. short do_error;
  595. long *exp_check;
  596. {
  597. register short i;
  598. register long chksum;
  599. long hchksum;
  600.  
  601. hchksum = untar_number(((barh_type*)buffer)->chksum,do_error);
  602. if(hchksum==-1) return -2;        /* testata non bar */
  603. chksum= ' ' * 8;    /* nel calcolo del checksum, il campo checksum era sostituito
  604.                     da spazi */
  605. for (i=0; i < 48; ++i)
  606.     chksum += (unsigned char)buffer[i];
  607. for (i+=8; i < sizeof(tarh); ++i)
  608.     chksum += (unsigned char)buffer[i];
  609.  
  610. *exp_check=chksum;
  611.  
  612. if (chksum == hchksum) return 0;    /* tutto OK */
  613.  
  614. /* il fatto e' questo: quando bar calcola il checksum del settore zero, il campo
  615. size contiene '0','\0'. Però, per un orribile bug, i 10 bytes successivi non vengono 
  616. affatto azzerati ma contengono ancora la parte finale del campo size del disco 
  617. precedente, e se il nuovo valore di size, che viene scritto DOPO aver calcolato il 
  618. checksum, è abbastanza lungo succede che parte dei bytes usati per il calcolo del 
  619. checksum vengono irrimediabilmente sovrascritti, e non ho più modo di calcolarlo 
  620. correttamente.
  621.  Ma d'altra parte a me fa molto comodo poter controllare il checksum, quindi mi rassegno
  622. al fatto che un errore può esserci, ma controllo che questo errore sia compatibile con
  623. questo comportamento errato, senza però strafare, in fondo altre versioni di bar
  624. potrebbero aver corretto il bug: cioè, controllo che il checksum letto sia giustificabile
  625. con un numero di cifre ottali <= del numero di caratteri sovrascritti dal nuovo valore
  626. di size, e ipotizzo anche che la correzione del bug consista nel calcolare il checksum
  627. quando sarebbe logico, dopo aver riscritto size.
  628.  
  629. -- The checksum computation of the volume header is one of the most 
  630. horrible aspects of bar (file headers are OK, fortunately). For some 
  631. unknown reason, bar saves the volume header in a reserved place, so
  632. the next volume header is built without reinitializing all fields:
  633. 1) the volume_num is updated
  634. 2) the size field is replaced by "0" (a '0' followed by a '\0'):
  635.    since that field is 12 bytes long, 10 bytes of the old value are not
  636.    altered by that operation
  637. 3) the checksum is computed and stored
  638. 4) the new value of size is now stored in the size field (strangely, since
  639.    file header checksums are always computed after filling all other fields):
  640.    since it's in octal and is multiple of 512, either it's 0 or it's at least 
  641.    4 bytes long, so it overwrites part of the non-fixed data used to compute 
  642.    the checksum
  643. Hence, the size field is not protected by the checksum (not a tragedy, the
  644. whole file data is not protected by any checksum...) and the cheksum is computed
  645. using some data which is no more stored on the current disk. In fact, bar 
  646. simply ignores the volume checksum, but it could check it by obliging you to 
  647. always insert all disks of the archive in the correct order (on the first disk the
  648. "old size" is 0, on other disks it's the previous size field partially overwritten
  649. by "0").
  650. But suntar allows you to insert disks in any order, starting extraction from
  651. any disk. Furthermore, it automatically distinguishes between a tar and bar
  652. archive, and the checksum of sector 0 looks like the better way to 
  653. guide the choice.
  654. Hence, this function returns:
  655. 0     OK, the checksum is valid for a file header (the write commands of suntar
  656.     computes checksums of volume headers as if they were file headers, by
  657.     updating the size field before computing the checksum)
  658. 1   the checksum is bad as a file header, but the error could be due to some 
  659.     binary zeros and some unknown octal digits overwritten by what is currently
  660.     in the size field: that is, it could be a valid checksum for a volume header
  661. -1  the checksum is invalid anyway
  662. -2  the checksum field did not contain an octal string
  663.  
  664. */
  665.  
  666. {
  667. register short s;
  668. s=0;
  669. for(i=0;((barh_type*)buffer)->size[i]!=0; ++i){
  670.     s+= (unsigned char)((barh_type*)buffer)->size[i];
  671.     }
  672. chksum -= s;
  673. }
  674.  
  675. if( hchksum<chksum || hchksum > chksum + (i+1)*'7' )    /* i contiene ancora la
  676.                             dimensione della stringa size, il +1 per il \0 in fondo */
  677.     return -1;    /* bad checksum */
  678.     /* there are still some values which are forbidden: e.g. there is a hole between
  679.     "7\0"=55 and "00"=96, however "7777777\0" is > "00000000" hence the last hole
  680.     occurs when there are 7 bytes */
  681. if(i+1 > 7) return 1;
  682. i= ((short)(hchksum-chksum))/'0';        /* that's the number of octal digits, supposing
  683.                                     that all other chars are binary zeros */
  684. if(i>=8) i=7;    /* "77777777"/'0' yields 8, but without doubts it contains 7 digits */
  685. if( (short)(hchksum-chksum) <= i*'7')
  686.     return 1;    /* l'errore è giustificabile con i caratteri sporcati dal bug di bar */
  687. return -1;
  688.  
  689. }
  690.  
  691.  
  692.  
  693. unsigned char guess_bar_linkflag()
  694. /* il campo prima del linkflag che in teoria dovrebbe essere vuoto in pratica è pieno
  695. e a volte sborda sul linkflag: a prima vista sembra che il linkflag sia scritto dopo, 
  696. era comunque sempre '0' per i file, ma '6' per una directory, invece del '5' che
  697. mi aspetterei secondo la codifica tar (un'altra volta era '5', ma quando il campo
  698. precedente non sborda è '\0'). Per di più, gli hard link (ma non quelli simbolici) hanno
  699. il campo size != 0 ( e il linkflag corretto, '1'), anche se poi non segue nessun byte. 
  700. Meglio continuare a fare a meno del linkflag nel capire che razza di entry è... 
  701.  
  702. -- second horrible feature of bar: the rdev field should always be binary zeros
  703. for conventional files and directories, hence it should not be of interest
  704. to a program running on the Macintosh. On the contrary, it contains data, and
  705. I don't know what that data means. The horrible thing is that when that number
  706. was negative, it's written anyway as a 32 bit unsigned octal number, and that
  707. occupies 12 bytes, overflowing the rdev field and overwriting the linkflag
  708. field: it happens often, about one time out of two (and files in the same 
  709. subdirectories tend to either have all the problem or not have it at all).
  710.  So, the linkflag field can't be relied upon, and it should have been the most
  711. important field of the header, the first thing to look at!
  712.  If the original bar succeed to survive to such a disaster, there must be a way:
  713. here is what we succeeded to guess by a lot of testing:
  714. 1) folders may be distinguished since their name ends in '/': that was easy
  715. 2) links can be distinguished since the linkname field is full: however,
  716.    unlike tar and unlike what the documentation of bar says, the linkname field
  717.    really starts at the first byte after the '\0' which terminates the string
  718.    in the name field. The simple solution of suntar 1.0, consider that as a
  719.    file entry, works for symbolic links (obviously creating an empty file during
  720.    extraction) but does not work for hard links, whose size field is not 0
  721.    even if the archive contains 0 bytes of their contents
  722. 3) anything else is considered to be a normal file
  723.  If there will be any problem in this approach, the fault is not ours: the
  724. fault is of that fellow who after doing such a blatant bug, did not correct
  725. it and allowed it to remain in a program which was used for years and is now
  726. at the version number 4.51, if I remember well. Obviously, if we could have a 
  727. look at the source of the original bar we would be surer of what we are doing,
  728. but that would not make the thing less horrible.
  729. */
  730. {
  731. short l;
  732. l=strlen(((barh_type*)disk_buffer)->name);
  733. if( ((barh_type*)disk_buffer)->name[l-1] == '/')
  734.     return '5';
  735. else if( ((barh_type*)disk_buffer)->name[l+1] ) /* perché il link name non sta 
  736.             affatto nel campo omonimo...
  737.             -- remember that the linkname is not placed in the linkname field */
  738.     return '1';
  739. else
  740.     return '0';
  741. }
  742.  
  743.  
  744. void unbar()
  745. {
  746. unsigned char linkflag;
  747. long exp_check;
  748.  
  749. disable_autoflush(1);
  750. if(expert_mode) print_sector_n(sect_n);
  751. sect_n++;
  752. more_in_bytes=0;
  753. if( unbar_checksum(&disk_buffer,1,&exp_check) != 0 ){
  754.     tarh.name[99]='\0';    /* non si sa mai che cosa ci sia...*/
  755.     printf("Bad header checksum ");
  756.     if(expert_mode){
  757.         if( print_if_string("(got %s expected ",((barh_type*)disk_buffer)->chksum,8))
  758.             printf("%lo) ",exp_check);
  759.         }
  760.     if(!ignore_errors) raise_error();
  761.     put_char('\n'); printf(s_spazi);
  762.     }
  763. strcpy(tarh.name,((barh_type*)disk_buffer)->name);
  764. copia_ultimo_header(disk_buffer,sect_n);
  765.  
  766. file_date= untar_number( &disk_buffer[36],false);
  767.  
  768. linkflag=guess_bar_linkflag();
  769.  
  770. if (linkflag=='5')
  771.     untar_directory();
  772. else if(linkflag=='1')
  773.     printf("Link %s -> %s%s\n", tarh.name,
  774.         &((barh_type*)disk_buffer)->name[strlen(((barh_type*)disk_buffer)->name)+1],
  775.         listonly?"":in_Italia?" (ignorato)":" (ignored)");
  776. else
  777.     untar_file(untar_number(((barh_type*)disk_buffer)->size,1));
  778. }
  779.  
  780. void copia_ultimo_header(p,sector_n)
  781. /* copies the first 184 bytes of the header where it must be copied, and 
  782. sets some related variables */
  783.  
  784. char*p;        /* puntatore al buffer contenente un header di file o directory */
  785. sector_t sector_n;    /* numero del settore che segue quello in cui l'header è stato scritto */
  786. {
  787. mcopy(ultimo_header,p,sizeof(ultimo_header));
  788. ultimo_header_valido=true;
  789. ultimo_disco_espulso=false;
  790. avail_sectors_for_file= sectors_on_floppy - sector_n;
  791. /* last_offset non è gestito qui, tocca al chiamante occuparsene
  792. -- last_offset is not assigned here, but it must be assigned by the caller
  793. */
  794. }
  795.  
  796. /*************************/
  797.  
  798. void bar_check_floppy_swap(situation)
  799. short situation;
  800. /* handle floppy swap for bar archives */
  801. {
  802. short i,this_floppy,accept_any_disk;
  803. sector_t previous_sect;
  804.  
  805. if(situation>0){    /* 1 => il primo settore dell'archivio; 0=>un altro settore richiesto da readblock 
  806.                     (entro un file); -1 => un altro settore richiesto per leggere un header
  807.                     -- situation =1 => the first sector in the archive; 0 => another 
  808.                     sector read through readblock; -1 => a sector which should contain
  809.                     a file header */
  810.     floppy_n=1;
  811.     sect_n=1;
  812.     if(fase==hack_listing){
  813.         this_floppy=bar_check_settore0(§_n,true);
  814.         if(this_floppy<0) raise_error();
  815.         if(sect_n>0)printf("%ld sectors from a previous file",sect_n);
  816.         sect_n++;
  817.         if(sect_n>=sectors_on_floppy){
  818.             printf(" (Partly on next disk)\n");    /* a very long file may be splitted
  819.                         in three or more disks... */
  820.             longjmp(main_loop,-1);    /* during Expert list, the disk is not 
  821.                         ejected...*/
  822.             }
  823.         else
  824.             printf("\n");
  825.         return;
  826.         }
  827.     /* e prosegui, per il controllo del settore 0
  828.     -- continue, to check sector 0 */
  829.     }
  830. else if(sect_n<sectors_on_floppy || !drive_number)
  831. /* the most common case: the requested sector is in the disk which is already
  832. in the drive */
  833.     return;
  834. else{
  835.     floppy_n++;
  836.     sect_n -= sectors_on_floppy-1;    /* -1 per via dell'header...; in modalità normale
  837.                                     si ottiene sempre 1, in listonly no !
  838.                                     -- minus 1 because of the header; during extraction, 
  839.                                     sect_n will be == sectors_on_floppy, during a List
  840.                                     it will not
  841.                                     */
  842.     if(fase==hack_listing){
  843.         if(file_aperto){
  844.             if(sect_n>1) printf(UNEXP);
  845.             else printf("\nEnd of file\n");
  846.             }
  847.         else{
  848.             if(sect_n>1) printf("(%ld sectors on next disk)\n",(long)sect_n-1);
  849.             printf("\nEnd of disk\n");
  850.             }
  851.         longjmp(main_loop,-1);
  852.         }
  853.     }
  854.  
  855. accept_any_disk= listonly || situation!=0;    /* cioè, non sono in mezzo ad un salvataggio...
  856.         if I'm in the middle of a file saving, to get next disk is more important */
  857.  
  858. for(;;){
  859.     if(situation<=0){    /* il primo disco è già dentro, gli altri bisogna sostituirli a
  860.                         ciò che è dentro...
  861.                         -- the first disk is already in the drive, further disks must
  862.                         be inserted
  863.                         */
  864.         if(file_aperto) raise_error();    /* dovrò metterci un messaggio di errore, 
  865.                 ma non ne ho voglia di farlo ora; idem per GNU... */
  866.         diskEject();
  867.         do{ 
  868.             if(fase==hack_reading)    /* succede solo per untar e unbar at sector */
  869.                 i=inserzione_assicurata(in_Italia?"\pInserisci il prossimo disco":
  870.                     "\pInsert next disk",accept_any_disk);
  871.             else{
  872.                 char buffer[40];
  873.                 strcpy(buffer,in_Italia?"Inserisci il disco numero ":"Insert disk number ");
  874.                 my_itoa((long)floppy_n,&buffer[strlen(buffer)]);
  875.                 i=inserzione_assicurata(my_c2pstr(buffer),accept_any_disk);
  876.                 }
  877.             }
  878.         while(i!=0);
  879.         }
  880.     else
  881.         situation=-2;    /* non posso lasciare 1 se resto entro il ciclo
  882.             -- it can't remain 1 inside the loop
  883.             */
  884.  
  885.     /* ora guardo se il disco ricevuto è quello che mi aspetto
  886.     -- check whether the inserted disk is the expected disk
  887.     */
  888.  
  889.     this_floppy= bar_check_settore0(&previous_sect,true);
  890.  
  891.     if(this_floppy==floppy_n ||
  892.        fase==hack_reading && previous_sect+avail_sectors_for_file==
  893.            ((untar_number(((barh_type*)ultimo_header)->size,-1)+511)/512) ){
  894.         /* è stato inserito il disco voluto: nel caso di unbar at sector non posso
  895.         fare affidamento sul numero di floppy, ma almeno le dimensioni le controllo */
  896.  
  897.         printf(in_Italia?"Disco numero %d":"Disk number %d",this_floppy);
  898.         print_if_string(in_Italia?" dell\'archivio %s":" of the archive %s",
  899.             ((barh_type*)disk_buffer)->name,100);
  900.         printf("\n");
  901.  
  902.         if(sect_n<sectors_on_floppy) return;
  903.         /* può capitare durante il list di un file che risulta suddiviso in più
  904.         di 2 dischi, allora chiede anche quelli intermedi ma al solo scopo di
  905.         sapere quanti settori ci sono
  906.         -- I may be here only during List of a file which is so long to be splitted
  907.         among at least three disks: suntar asks all the disks, but the intermediate 
  908.         ones are ejected soon after reading how many sectors they contain (it's not
  909.         forbidden to use disks of different sizes for a single archive)
  910.         */
  911.         if(sect_n>=sectors_on_floppy)
  912.             printf(in_Italia?"Disco occupato completamente da parte di un file precedente\n":
  913.                 "The whole disk is occupied by part of a previous file\n",
  914.                 ((tarh_type*)ultimo_header)->name);
  915.         floppy_n++;
  916.         sect_n -= sectors_on_floppy-1;
  917.         avail_sectors_for_file += sectors_on_floppy-1;
  918.         situation = -1;
  919.  
  920.         }
  921.     else if(this_floppy<0){
  922.         if(situation==-2)
  923.             raise_error();        /* l'utente può ridare il comando senza rimetterci nulla
  924.                 -- the user may repeat the command and return here in this same situation */
  925.         else
  926.             ;    /* non è un disco bar, non c'è che riprovare...
  927.                 not a bar disk: remain in the loop, so it will be ejected and a new one
  928.                 will be asked for
  929.                 */
  930.         }
  931.     else{
  932.         /* it's not the right disk, but it's a bar disk */
  933.         printf(in_Italia?"Questo è il floppy numero %d\n":"Disk number %d\n",this_floppy);
  934.         if(!accept_any_disk){
  935.             beep_in_foreground();
  936.             if(fase!=hack_reading)
  937.                 printf(in_Italia?"Errore, io voglio il floppy %d, non il %d\n":
  938.                 "Error, requested disk is number %d, not %d\n",floppy_n,this_floppy);
  939.             else
  940.                 printf("Wrong disk !\n");
  941.             }
  942.         else{
  943.             char pt[6];
  944.             my_itoa((long)floppy_n,&pt[1]);
  945.             pt[0]=strlen(pt+1);
  946.             if( chiedi_su_questo(this_floppy,previous_sect,NULL,
  947.                 in_Italia?"\pLeggo questo disco invece del ":
  948.                 "\pMust I use this disk rather than disk ",pt,"\p ?") ){
  949.                 floppy_n=this_floppy;
  950.                 sect_n = previous_sect;
  951.                 ultimo_header_valido=false;
  952.                 sect_n++;    /* per tener conto anche del settore 0 */
  953.                 return;
  954.                 }
  955.             }
  956.         }
  957.     }
  958. }
  959.  
  960. short inserzione_assicurata(mesg,accept_any_disk)
  961. /* as aspetta_inserzione but it never returns without a new disk inserted, 
  962. it rather calls raise_error: if a file is being saved, it asks for confirmation,
  963. since an error closes all open files and hence truncates them */
  964. char*mesg;
  965. Boolean accept_any_disk;
  966. {
  967. /* come aspetta inserzione ma non ritorna al chiamante, usando longjmp, se il disco
  968. non viene affatto inserito ed è accettabile che non lo sia */
  969.     short i;
  970.     do{
  971.         i=aspetta_inserzione(mesg,false);
  972.         if(i!=0){
  973.             if(!accept_any_disk){
  974.                 ParamText(in_Italia?"\pVa bene lasciare il file incompleto ?":
  975.                     "\pDo you want to let this file uncompleted ?",PNS,PNS,PNS);
  976.                 if(my_modal_dialog(130,titoli,2)==1)
  977.                     raise_error();
  978.                 else
  979.                     return i;
  980.                 }
  981.             else
  982.                 raise_error();
  983.             }
  984.         if(di.is_not_initialized) diskEject();
  985.         }
  986.     while(di.is_not_initialized);
  987.     return 0;
  988. }
  989.  
  990.  
  991. short bar_check_settore0(previous_sect,verbose)
  992. /* examine if sector 0 is a valid bar volume header */
  993. sector_t *previous_sect;
  994. Boolean verbose;
  995. {
  996. short disk_n;
  997. long offset,exp_check;
  998.  
  999. leggi_settore(0,disk_buffer);
  1000. if(check_error()) return err_code;
  1001.  
  1002. offset=untar_number(((barh_type*)disk_buffer)->size,-1);
  1003.  
  1004. if(my_atoi(((barh_type*)disk_buffer)->volume_num,&disk_n) ) disk_n = -1;
  1005.  
  1006. if(((barh_type*)disk_buffer)->bar_magic[0]!= 'V' || 
  1007.    ((barh_type*)disk_buffer)->bar_magic[1] != 0 || disk_n==-1 || offset==-1){
  1008.     if(verbose){
  1009.         beep_in_foreground();
  1010.         printf(in_Italia?"Questo non è un disco in formato bar\n":"Not a bar disk !\n");
  1011.         }
  1012.     return -1;
  1013.     }
  1014.  
  1015. *previous_sect=(offset+511)/512; /* è un multiplo di 512, ma non fidarsi è meglio */
  1016. /* se fosse previous_sect = 0 (se l'ultimo settore di un disco è un header...) allora
  1017. permettere di estrarre anche questo file !!*/
  1018.  
  1019. if( unbar_checksum(disk_buffer,-1,&exp_check) <0 ){
  1020.     if(verbose){
  1021.         printf("Bad disk header checksum");
  1022.         if(expert_mode){
  1023.             if( print_if_string(" (got %s expected ",((barh_type*)disk_buffer)->chksum,8))
  1024.                 printf("%lo)",exp_check);
  1025.             }
  1026.         printf("\n");
  1027.         if( ! ignore_errors ) return -1;
  1028.         }
  1029.     else
  1030.         return -1;
  1031.     }
  1032. return disk_n;
  1033. }
  1034.  
  1035. static Boolean chiedi_su_questo(this_floppy,previous_sect,name,p1,p2,p3)
  1036. /* presents the modal dialog "must I continue on this disk ?" */
  1037. short this_floppy;
  1038. sector_t previous_sect;
  1039. char*name;
  1040. Str255 p1,p2,p3;
  1041. {
  1042. enum {dOK=1,dNo};
  1043. switch(my_semimodal_dialog(129,titoli,2,p1,p2,p3)){
  1044. case dOK:
  1045.     if(this_floppy>1&&previous_sect>0){
  1046.         printf(in_Italia?"Presenti %ld settori di completamento di "
  1047.             :"%ld sectors from ",(long)previous_sect);
  1048.         if(name==NULL)
  1049.             printf(in_Italia?"un file precedente\n":"a previous file\n");
  1050.         else
  1051.             printf("%s\n",name);
  1052.         }
  1053.     return 1;
  1054. case dNo:
  1055.     return 0;
  1056. }
  1057. }
  1058.  
  1059. /*******************************/
  1060.  
  1061. void tar_check_floppy_swap(situation)
  1062. short situation;
  1063. /* check disk swap for GNU tar or AIX tar archives.
  1064. Many comments are identical to those in bar_check_floppy_swap, hence they were not
  1065. translated */
  1066. {
  1067. /* in questa routine, floppy_n puo' valere solo 1 o 2, non vado a contare i floppy.
  1068. Però, se capita che un disco che non sia il primo abbia di nuovo un header di file
  1069. al settore 0, devo rimetterlo ad 1 perché non avrò l'header di continuazione
  1070. -- floppy_n may have only two values: 1 for disks without an 'M' continuation
  1071. header (such as the first disk) and 2 for a disk which has one (as most of the 
  1072. following disks)
  1073. */
  1074.  
  1075. short i,this_floppy,accept_any_disk;
  1076. sector_t previous_sect;
  1077. static char s1[]="Disco occupato completamente da parte di %s\n",
  1078.             s2[]="The whole disk is occupied by a part of %s\n";
  1079.  
  1080. if(situation>0){    /* 1 => il primo settore dell'archivio;
  1081.                     0 => un altro settore richiesto da readblock (entro un file);
  1082.                     -1 => un altro settore richiesto per leggere un header;
  1083.                     -2 => il parametro di ingresso era 1 ma ho dovuto espellere
  1084.                         il disco perché non buono */
  1085.     floppy_n=1;
  1086.     previousFormat=tar_unknown;
  1087.     ultimo_header_valido=false;
  1088.     sect_n=0;
  1089.     if(fase==hack_listing){
  1090.         if(next_header_for_AIX!=-1){
  1091.             sect_n=next_header_for_AIX;    /* hacking() has already checked that's a good
  1092.                                 starting sector */
  1093.             return;
  1094.             }
  1095.         accept_any_disk= true;
  1096.         this_floppy=tar_check_settore0(true);
  1097.         if(this_floppy<0)
  1098.             raise_error();
  1099.         if(this_floppy==2){
  1100.             sect_n= (untar_number(((tarh_type*)disk_buffer)->size,false)+511)>>9;
  1101.             if(sect_n>0)printf("%ld sectors from %s",    /* se il file è lunghissimo non
  1102.                     è vero, non sono tutti qui ! Lo scrivo sotto */
  1103.                 (long)sect_n,((tarh_type*)disk_buffer)->name);
  1104.             sect_n++;
  1105.             }
  1106.         if(hasVheader) sect_n++;
  1107.         if(sect_n>=sectors_on_floppy){
  1108.             printf(" (Partly on next disk)\n");
  1109.             longjmp(main_loop,-1);
  1110.             }
  1111.         printf("\n");
  1112.         return;
  1113.         }
  1114.     accept_any_disk= true;
  1115.     }
  1116. else if(sect_n<sectors_on_floppy || !drive_number)
  1117.     return;
  1118. else{
  1119.     accept_any_disk= listonly || situation!=0;
  1120.     floppy_n=2;
  1121.     sect_n -= sectors_on_floppy;    /* in modalità normale si ottiene sempre 0, in listonly no !*/
  1122.     if(situation==-1 && sect_n==0){        /* in questo caso l'header di continuazione non c'è
  1123.                 -- if the last sectors of a file happens to be written in the last
  1124.                 sector of a disk, the following disk has not a continuation header, hence
  1125.                 it looks like the first disk of another archive */
  1126.         floppy_n=1;
  1127.         /*sect_n--; no, chiedo comunque il 0, sta poi alla gestione dell'inserzione
  1128.                     prossimo disco saltare eventuali header */
  1129.         }
  1130.     if(fase==hack_listing){
  1131.         if(file_aperto){
  1132.             if(sect_n>0)
  1133.                 printf(UNEXP);
  1134.             else
  1135.                 printf("\nEnd of file\n");
  1136.             }
  1137.         else{
  1138.             if(sect_n>0)
  1139.                 printf("(%ld sectors on next disk)\n",(long)sect_n);
  1140.             printf("\nEnd of disk\n");
  1141.             }
  1142.         longjmp(main_loop,-1);
  1143.         }
  1144.     }
  1145.  
  1146. for(;;){
  1147.     if(situation<=0){    /* il primo disco è già dentro, gli altri bisogna sostituirli a
  1148.                         ciò che è dentro... */
  1149.         if(file_aperto) raise_error();
  1150.         diskEject();
  1151.         if(tar_version==tar_unknown &&previousFormat==tar_unknown){
  1152.             ParamText(in_Italia?
  1153.                 "\pQuesto è un archivio multidisco ?":
  1154.                 "\pIs this a multivolume archive ?",PNS,PNS,PNS);
  1155.             assegna_tar_version();
  1156.             }
  1157.         if(tar_version==tar_singlevol && previousFormat==tar_unknown)
  1158.             error_message(in_Italia?"Errore: raggiunta la fine del disco\n":
  1159.                 "Error: end of disk was reached\n");
  1160.  
  1161.         do{
  1162.             i=inserzione_assicurata(situation==-2 ? (
  1163.                 in_Italia?"\pInserisci il disco in formato tar":
  1164.                 "\pInsert the disk in tar format") :
  1165.                 (in_Italia?"\pInserisci il prossimo disco tar":
  1166.                 "\pInsert next tar disk"), accept_any_disk);
  1167.             }
  1168.         while(i!=0);
  1169.         }
  1170.     else
  1171.         situation=-2;    /* non posso lasciare 1 se resto entro il ciclo */
  1172.  
  1173.     if(situation!=-2 && (previousFormat==tar_AIX ||
  1174.        previousFormat==tar_unknown && tar_version==tar_AIX) ){
  1175.         /* an AIX disk has no header, hence I can't be sure that it's the right
  1176.         disk, I must rely on the current setting of the option */
  1177.         previousFormat=tar_AIX;
  1178.         this_floppy=2;
  1179.         previous_sect=0;
  1180.         if(sect_n >= sectors_on_floppy){        /* la solito, può succedere per un List */
  1181.             sect_n -= sectors_on_floppy;
  1182.             printf(in_Italia? s1:s2,((tarh_type*)ultimo_header)->name);
  1183.             continue;        /* the disk must be ejected, continuing on next one */
  1184.             }
  1185.         /* if(qualche controllo che sia veramente AIX.....) */
  1186.         return;
  1187.         }
  1188.  
  1189.     this_floppy= tar_check_settore0(true);
  1190.     previous_sect=0;
  1191.  
  1192.     if(floppy_n==2 && this_floppy==2 && 
  1193.        verifica_nome(hasVheader,&previous_sect)!=noErr ) this_floppy=3; /* any value 
  1194.                    which can't be equal to floppy_n */
  1195.     if(this_floppy==floppy_n){        /* è stato inserito il disco voluto */
  1196.  
  1197.         if(hasVheader) sect_n++;        /* devo incrementare sect_n per saltare l'header di 
  1198.                     volume, ed è più flessibile non farlo in tar_check_settore0,
  1199.                     non posso farlo se il disco non viene accettato e l'ultima
  1200.                     decisione su questo la prendo qui
  1201.                     -- I could not do that in tar_check_settore0, since it can't
  1202.                     know whether the disk is the right one or not */
  1203.         if(floppy_n==2) sect_n++;    /* salto anche l'header extra... */
  1204.         avail_sectors_for_file = sectors_on_floppy;
  1205.         if(hasVheader) avail_sectors_for_file--;        /* perché quei settori non sono */
  1206.         if(this_floppy>=2) avail_sectors_for_file--;    /*usati per il file */
  1207.         if(sect_n<sectors_on_floppy)
  1208.             return;
  1209.  
  1210.         /* può capitare durante il list di un file che risulta suddiviso in più
  1211.         di 2 dischi, allora chiede anche quelli intermedi ma al solo scopo di
  1212.         sapere quanti settori ci sono */
  1213.         printf(in_Italia? s1:s2,((tarh_type*)ultimo_header)->name);
  1214.         sect_n -= sectors_on_floppy;    /* gli incrementi a sect_n per gli header extra
  1215.                                     sono già stati effettuati OK */
  1216.         floppy_n=2;
  1217.         if(situation==-1 && sect_n==1)
  1218.             floppy_n=1;
  1219.         /* e proseguo, esattamente come se ci fosse stato un errore e fosse stato 
  1220.         inserito il disco sbagliato, solo che i dati di controllo sono stati
  1221.         aggiornati a pretendere il disco successivo */
  1222.         }
  1223.     else if(this_floppy<0){
  1224.         /* printf(in_Italia ? "Il disco non è in formato tar né bar\n" : 
  1225.             "Disk format is neither tar nor bar\n"); no, qualcosa viene scritto da
  1226.             bar_check_settore_zero (magari tramite check_error o untar_number) */
  1227.         if(situation==-2){
  1228.             raise_error();        /* l'utente può ridare il comando senza rimetterci nulla */
  1229.             }
  1230.         else
  1231.             printf(in_Italia?"Riprova !\n":"Try again !\n");    /* disco non tar, non c'è che riprovare... */
  1232.         }
  1233.     else{
  1234.         if(!accept_any_disk){
  1235.             beep_in_foreground();
  1236.             printf(in_Italia?"Errore, non è il floppy successivo!\n":
  1237.             "Error, it\'s not next disk!\n");
  1238.             }
  1239.         else{
  1240.             if(this_floppy==1)
  1241.                 previous_sect=0;
  1242.             else
  1243.                 previous_sect= (untar_number(((tarh_type*)disk_buffer)->size,false)+511)>>9;
  1244.             if( chiedi_su_questo(this_floppy,previous_sect,((tarh_type*)disk_buffer)->name,
  1245.                 situation==-2 ? (in_Italia?"\pInizio da questo disco ?":
  1246.                     "\pMust I start from this disk ?") :
  1247.                 (in_Italia?"\pContinuo su questo disco ?":
  1248.                     "\pMust I continue on this disk ?") ,PNS,PNS) ){
  1249.                 if(this_floppy==1){
  1250.                     ultimo_header_valido=false;    /* tanto gestisco subito il primo buono */
  1251.                     avail_sectors_for_file=sectors_on_floppy-sect_n;
  1252.                     }
  1253.                 else{
  1254.                     long last_size;
  1255.                     copia_ultimo_header(disk_buffer,hasVheader?2:1);
  1256.                     last_offset=untar_number(((tarh_type*)disk_buffer)->offset,-1);
  1257.                     last_size=untar_number(((tarh_type*)ultimo_header)->size,false);
  1258.                     ((tarh_type*)ultimo_header)->linkflag='\0';
  1259.                     numstr (((tarh_type*)ultimo_header)->size,last_size+last_offset,12);
  1260.                     }
  1261.                 if(this_floppy==3) this_floppy=2;
  1262.                 floppy_n=this_floppy;
  1263.                 sect_n = previous_sect;
  1264.                 if(hasVheader) sect_n++;
  1265.                 if(this_floppy>=2) sect_n++;
  1266.                 if(sect_n<sectors_on_floppy){
  1267.                     if(this_floppy==1) printf(in_Italia ? "Parte finale del file %s\n":
  1268.                         "Last part of file %s\n",((tarh_type*)ultimo_header)->name);
  1269.                         /* if it's !=1, the message is in chiedi_su_questo */
  1270.                     return;
  1271.                     }
  1272.                 sect_n-=sectors_on_floppy;
  1273.                 if(this_floppy!=1) printf(in_Italia ? s1: s2, ((tarh_type*)ultimo_header)->name);
  1274.                 }
  1275.             }
  1276.         }
  1277.     }
  1278. }
  1279.  
  1280. short tar_check_settore0(verbose)
  1281. /* examine the first sector of a tar disk: either it's all zeros, or a normal
  1282. file header, or a continuation file header. If it's a 'V' volume header, then
  1283. check sector 1 too
  1284. */
  1285. Boolean verbose;
  1286. {
  1287. short i;
  1288.  
  1289. hasVheader=0;
  1290. leggi_settore(0,disk_buffer);
  1291. if(check_error()) return err_code;
  1292.  
  1293. if(check_all_zero(disk_buffer)) return 1;        /* un archivio tar vuoto... */
  1294. if( (i=untar_checksum(disk_buffer,-1,verbose)) < 0){
  1295.     if(i==-2||!verbose|| !ignore_errors) return -1;
  1296.     }
  1297.  
  1298. hasVheader = ((tarh_type*)disk_buffer)->linkflag=='V';
  1299. if(hasVheader){
  1300.     previousFormat=tar_GNU;
  1301.     disk_buffer[99]=0;
  1302.     if(verbose){
  1303.         if(fase==hack_listing){
  1304.             long cdate=untar_number(((tarh_type*)disk_buffer)->mtime,-1);
  1305.             if(cdate!=-1) print_one_date(cdate+UNIXTIME,in_Italia?"Archivio creato ":
  1306.                 "Archive created ");
  1307.             printf(in_Italia?"; i":"; t");
  1308.             }
  1309.         else
  1310.             printf(in_Italia?"I":"T");
  1311.         printf(in_Italia?"l nome del disco è %s\n":
  1312.         "he disk name is %s\n",disk_buffer);    /* stampa l'informazione contenuta nell'header ! 
  1313.         -- that's the string the user specified in the V option, plus the volume number */
  1314.         }
  1315.     leggi_settore(1,disk_buffer);
  1316.     if(check_error()) return err_code;
  1317.     if(check_all_zero(disk_buffer)) return 1;
  1318.     if( (i=untar_checksum(disk_buffer,-1,verbose&&!ignore_errors)) < 0){
  1319.         if( (i==-2 || !ignore_errors) && verbose ) return -1;
  1320.             /* verbose is false if and only if I were called by identify format,
  1321.             which only wants to know if this is a tar archive, not if its sector 1
  1322.             is corrupted */
  1323.         }
  1324.     }
  1325.  
  1326. if(((tarh_type*)disk_buffer)->linkflag=='M'){
  1327.     previousFormat=tar_GNU;
  1328.     return 2;
  1329.     }
  1330. else
  1331.     return 1;
  1332. }
  1333.  
  1334. static OsErr verifica_nome(volume_header,previous_sect)
  1335. /* verify a continuation header against the normal header which was in the previous disk */
  1336. short volume_header;
  1337. sector_t *previous_sect;
  1338. {
  1339. long last_size,sizeleft,expected_offset;
  1340.  
  1341. if(!ultimo_header_valido){
  1342.     *previous_sect=0;
  1343.     return noErr;        /* non ho visto il disco precedente, perché
  1344.         sono alla prima inserzione */
  1345.     }
  1346. sizeleft=untar_number(((tarh_type*)disk_buffer)->size,false);
  1347. last_size=untar_number(((tarh_type*)ultimo_header)->size,false);
  1348. *previous_sect=(sizeleft+511)>>9;
  1349. if( strcmp(ultimo_header,disk_buffer) ) return -1;    /* il nome non coincide */
  1350.  
  1351. expected_offset=last_offset+((long)avail_sectors_for_file<<9);
  1352. last_offset=untar_number(((tarh_type*)disk_buffer)->offset,false);
  1353. /*printf("<%ld %ld,%ld,%ld,%ld>",(long)avail_sectors_for_file,expected_offset,last_offset,last_size,sizeleft);*/
  1354.  
  1355. if(expected_offset!=last_offset || last_size-last_offset!=sizeleft) return -1;
  1356.  
  1357. if(volume_header)
  1358.     (*previous_sect)++;
  1359.  
  1360. return noErr;
  1361. }
  1362.  
  1363. void delete_out_file(void);
  1364. static void delete_out_file()
  1365. {
  1366. reinit_hd_buffering();
  1367. cancella_file_aperto(pb.ioParam.ioRefNum);
  1368. devo_chiudere_out=false;
  1369. }
  1370.  
  1371. void close_or_del_out_file()
  1372. {
  1373. if(devo_chiudere_out){
  1374.     if(del_incompl)
  1375.         delete_out_file();
  1376.     else{
  1377.         flush_hd_buffer();
  1378.         PBCloseSync(&pb);
  1379.         }
  1380.     devo_chiudere_out=false;
  1381.     }
  1382. }
  1383.  
  1384. /******************************************************************/
  1385.  
  1386. short filter_conf(EventRecord*);
  1387. static short filter_conf(theEvent)
  1388. EventRecord*theEvent;
  1389. {
  1390. /* the standard filter for semimodal makes CR equivalent to button 1,
  1391. this filter makes esc equivalent to button 2 */
  1392. #define ESC 27
  1393. if(theEvent->what==keyDown&&(char)theEvent->message==ESC)
  1394.     return 2;
  1395. return 0;
  1396. }
  1397.  
  1398.  
  1399. void check_confirmation()
  1400. /* handles the confirm saves dialog */
  1401. {
  1402. /* il nome del file DEVE stare in tarh.name, formato C
  1403. -- the file name MUST be a C string in tarh.name
  1404.  */
  1405. static Point wPos={-1,-1};
  1406. static char *t_ita[]= {"\pSalva","\pNon salvare","\pSalva tutto","\pSalta tutto",
  1407.     "\pContinua altrove","\pTermina estrazione"};
  1408. char buffer[120];
  1409.  
  1410. if(!confirm_saves||all_listonly||fase==hack_reading||
  1411.     fase==hack_listing||fase==selected_reading || file_aperto>ff_tarbar ) 
  1412.     return;
  1413. else{
  1414.     short item;
  1415.     enum {cdSave=1,cdSkip,cdSaveAll,cdSkipAll};
  1416.  
  1417.     strcpy(buffer,"File\312");    /* spazio non interrompibile
  1418.                                 -- non-breakable space: if the file name is long,
  1419.                                 breaking between lines here is not a wise thing */
  1420.     strcat(buffer,tarh.name);
  1421.     my_c2pstr(buffer);
  1422.  
  1423.     do{
  1424.         item=semimodalDialog(136,&wPos,filter_conf,t_ita,6,buffer,NULL,NULL,
  1425.             teJustLeft,true,NULL);
  1426.         if(item==6)
  1427.             select_directory();
  1428.         else if(item==7){
  1429.             extern long last_selection;
  1430.             last_selection = menuItemMess(fileID,fmAbort);
  1431.             raise_error();
  1432.             }
  1433.         }
  1434.     while(item>4);
  1435.  
  1436.     listonly= item==cdSkip || item==cdSkipAll;
  1437.     if(item==cdSaveAll || item==cdSkipAll)
  1438.         set_skip_all(1);
  1439.     }
  1440. }
  1441.  
  1442. void check_conf_dir(dname)
  1443. char*dname;
  1444. {
  1445. /* in confirm saves directories are extracted only if they already existed.
  1446. OK, that seems the opposite of any logical thing, but when extracting, for example,
  1447. dir/file if dir does not exist it's created. Hence, if I wish to extract files
  1448. which go to that directory it will be created anyway, hence not creating it
  1449. avoids an almost useless dialog, but I should warn the user
  1450. before placing files in a directory which already existed (that could cause a
  1451. chaotic mix of files). The simplest way to do that warning is calling create_directory...
  1452. */
  1453. if(!confirm_saves||all_listonly||fase==hack_reading||
  1454.     fase==hack_listing||fase==selected_reading) 
  1455.     return;
  1456. {
  1457. CInfoPBRec cinfo;
  1458. short i;
  1459. cinfo.dirInfo.ioNamePtr= my_c2pstr(dname);
  1460. #ifdef USA_CURRVREFN
  1461. cinfo.dirInfo.ioVRefNum=curr_vrefnum;
  1462. #else
  1463. cinfo.dirInfo.ioVRefNum=0;
  1464. #endif
  1465. cinfo.dirInfo.ioFDirIndex=0;
  1466. cinfo.dirInfo.ioDrDirID=0;
  1467. listonly= PBGetCatInfoSync(&cinfo)!=noErr;
  1468. my_p2cstr(dname);
  1469. }
  1470. }
  1471.  
  1472. /********************************/
  1473. void my_itoa(val,buffer)
  1474. register long val;
  1475. char *buffer;
  1476. {
  1477. char buf[14];
  1478. Boolean nega;
  1479. register char *p=&buf[13];
  1480. if(nega= (val<0) )
  1481.     val= -val;
  1482. *p='\0';
  1483. do{
  1484.     *--p ='0'+(short)(val%10);
  1485.     val /= 10;
  1486.     }
  1487. while(val>0);
  1488. if(nega) *--p='-';
  1489. strcpy(buffer,p);
  1490. }
  1491.  
  1492. static short isMacBin2(buf)
  1493. /* checks whether the MacBinary header is a MacBinary II header;
  1494. returns 0 for non-MacBinary II
  1495. 1 for Macbinary II
  1496. -1 for an unknown (future) release of MacBinary II that suntar can't decode,
  1497. -2 for CRC error
  1498.  */
  1499. register unsigned char *buf;
  1500. {
  1501. extern short current_crc;
  1502. register short i;
  1503. /* can't declare a pointer to binh_type since it's misaligned by one byte */
  1504. if(buf[122]<129 || buf[123]<129) return 0;
  1505. if(buf[123]>129) return -1;
  1506. current_crc=0;
  1507. for(i=0;i<124;i++)
  1508.     CalcCRC(buf[i]);
  1509. CalcCRC(0);
  1510. CalcCRC(0);
  1511. if( current_crc != *(short*)&buf[124]) return -2;
  1512. return 1;
  1513. }
  1514.  
  1515. void clear_unused_fields()
  1516. {
  1517. /* leggere documentazione su MacBinary II, ma non azzero busy perché 
  1518.     nel System 7 ha cambiato significato
  1519. -- the file macbinary2-standard.txt, reporting the decisions of the people
  1520. who met to set the standard, explains:
  1521. >All Finder flags and information would be uploaded, however, a downloading
  1522. >program should clear the Finder flag bits of
  1523. >  0 - Set if file/folder is on the desktop (Finder 5.0 and later)
  1524. >  1 - bFOwnAppl (used internally)
  1525. >  8 - Inited (seen by Finder)
  1526. >  9 - Changed (used internally by Finder)
  1527. > 10 - Busy (copied from File System busy bit)
  1528.  
  1529. >Also, fdLocation and fdFldr should be zeroed
  1530.  
  1531. Bit    Meaning (from Technical Note 40)
  1532. 0    Set if file/folder is on the desktop (Finder 5.0 and later)
  1533. 1    bFOwnAppl (used internally)
  1534. 2    reserved, currently unused
  1535. 3    reserved, currently unused
  1536. 4    bFNever (never SwitchLaunch) (not implemented)
  1537. 5    bFAlways (always SwitchLaunch) 
  1538. 6    Set if application is shared and is opened read-only (128K ROM only)
  1539. 7    Set if file should be cached (not implemented)
  1540. 8   Inited (seen by Finder)
  1541. 9   Changed (used internally by Finder)
  1542. 10  Busy (copied from File System busy bit)
  1543. 11  NoCopy (not used in 5.0 and later, formerly called BOZO)
  1544. 12  System (set if file is a system file)
  1545. 13  HasBundle
  1546. 14  Invisible
  1547. 15  File Locked
  1548.  
  1549. However, in System 7 bit 10 means "hasCustomIcon" and it's better to preserve it.
  1550. It's unfortunate that the MacBinary standard did not include a field for "version
  1551. of Finder which created it", now that different versions of the Finder use the same bits
  1552. for different purposes: luckily, if that file does have a custom icon its resource
  1553. fork contains a 'ICN#' resource with ID -16455.
  1554. And bit 15 should not be cleared according to the standard, but in System 7 it means
  1555. "is an alias" and it's correct to clear it when transferring an old file to
  1556. system 7, if the file does not contain an 'alis' resource.
  1557. As a result, I MUST examine the resource fork of the file if either bit 10 or 15
  1558. are set.
  1559. Bit 11 is now "is stationery pad": it's better to preserve it anyway, since the old
  1560. meaning is obsolete since Finder 5.0, there is no particular contents to check for
  1561. and the user may change it by a Get Info
  1562. Bit 12 was "is System file" and is now "Name locked": since it would be useless
  1563. to download an old system file to a machine with System 7, under System 7 it's
  1564. better to preserve it, but under system 6 ?
  1565. */
  1566.  
  1567.     macbinh.finfo.fdFlags &= ~0x303;
  1568.     *(long*)&macbinh.finfo.fdLocation=0;
  1569.     macbinh.finfo.fdFldr=0;
  1570.  
  1571.     if(macbinh.finfo.fdFlags & 0x8400){
  1572.         if(macbinh.rflen==0 || 
  1573.            !(macbinh.finfo.fdFlags & 0x400)&&(macbinh.dflen>0||macbinh.rflen>4096) )
  1574.            /* an alias file has no data fork and is not very big */
  1575.             macbinh.finfo.fdFlags &= ~0x8400;
  1576.         else{
  1577.             unsigned char name[64];
  1578.             short refnum,oldvRefNum,oldres;
  1579.             SetResLoad(false);        /* it should save the old status to restore
  1580.                     it, but it should never be false... */
  1581.             if(GetVol (&name,&oldvRefNum)!=noErr) oldvRefNum=0;
  1582.  
  1583.               SetVol(NULL,pb.fileParam.ioVRefNum);
  1584.               oldres=CurResFile();
  1585.               refnum= OpenResFile(pb.fileParam.ioNamePtr);
  1586.               if(refnum==-1)
  1587.                   macbinh.finfo.fdFlags &= ~0x8400;    /* clear both flags */
  1588.               else{
  1589.                 if(macbinh.finfo.fdFlags & 0x8000){    /* alias bit */
  1590.                     if(! Count1Resources ('alis') )
  1591.                         macbinh.finfo.fdFlags &= ~0x8000;
  1592.                     else if(!gHasResolveAlias){
  1593.                         ParamText(in_Italia?
  1594.                         "\pQuesto file è un alias, solo il System 7 può utilizzarlo":
  1595.                         "\pThis file is an alias, only System 7 knows how to use it",PNS,PNS,PNS);
  1596.                         my_alert();
  1597.                         }
  1598.                     }
  1599.                 if(macbinh.finfo.fdFlags & 0x400){    /* "has custom icon" bit */
  1600.                     Handle h = Get1Resource('ICN#',-16455);
  1601.                     if(h!=NULL)
  1602.                         ReleaseResource(h);
  1603.                     else
  1604.                         macbinh.finfo.fdFlags &= ~0x400;
  1605.                     }
  1606.                 CloseResFile(refnum);
  1607.                 }
  1608.             if(oldvRefNum) SetVol (&name,oldvRefNum);
  1609.             UseResFile(oldres);
  1610.             SetResLoad(true);
  1611.             }
  1612.         }
  1613. }
  1614.  
  1615.  
  1616. static char BadNameFolder[]=":bad names folder:";
  1617.  
  1618. static void make_badname(fname,name)
  1619. /* creates a new name for a file which caused a bad name error (some
  1620. versions of UNIX have a max name length which is greater than that of the HFS,
  1621. and it happens to see public domain Mac files with a very long name which 
  1622. would not be legal on a Macintosh)
  1623. */
  1624. char*fname,*name;
  1625. {
  1626. static short bad_names=0;
  1627. register char *p1,*p;
  1628. register short i;
  1629.  
  1630. strcpy(fname,BadNameFolder);
  1631. my_itoa((long)++bad_names,&fname[sizeof(BadNameFolder)-1]);
  1632.  
  1633. p1= name;
  1634. p=&p1[(unsigned char)*p1];    /* last character of original name */
  1635. p1=p1+1;
  1636. while(*p==':' && p>p1) p--;        /* typically, at the end of a Mac name there may be */
  1637. i = *p!=':';    /* 0-1 */
  1638. while(p>p1 && p[-1]!=':' && i<=29-strlen(&fname[sizeof(BadNameFolder)-1]) ){
  1639.     p--; i++;
  1640.     }
  1641. p1=fname + strlen(fname);
  1642. if(i){
  1643.     *p1++ ='-';
  1644.     while(i-- >0){
  1645.         if(*p>=' ' && *p< 127) *p1++ = *p;
  1646.         p++;
  1647.         }
  1648.     }
  1649. *p1='\0';
  1650.  
  1651. printf(in_Italia?"%P: nome non valido, cambiato in %s\n":
  1652.     "%P: bad name, renamed to %s\n",name,fname);
  1653. }
  1654.  
  1655. static Boolean is_bad_name(name)
  1656. char *name;
  1657. {
  1658. if(strlen(name)<sizeof(BadNameFolder) ) return false;
  1659. return ! strncmp(name,BadNameFolder,sizeof(BadNameFolder)-1);
  1660. }
  1661.  
  1662. static Boolean too_long(fname)
  1663. register char *fname;
  1664. {
  1665. register short i=0;
  1666. while(*fname!='\0'){
  1667.     if(*fname==':')
  1668.         i=0;
  1669.     else
  1670.         if(++i>31) return true;
  1671.     fname++;
  1672.     }
  1673.  return false;
  1674. }
  1675.  
  1676. static Boolean is_gif_file(fsize)
  1677. long fsize;
  1678. {
  1679. /* checks whether the file begins with 'GIF'
  1680. (really, the signature is GIF87a or GIF89a, but when there will be a GIF9xa
  1681. it will be better to recognize it too)
  1682. (This "privilege" is  because gif files are very popular, and since they are 
  1683. a non-Mac format usually they are downloaded as data only so they have no 
  1684. type and creator)
  1685. */
  1686. static char h[]={'G','I','F'};
  1687. if (fsize>100 && !strncmp(h,disk_buffer,(size_t)3) && 
  1688.     disk_buffer[3]>='0' && disk_buffer[3]<='9' && 
  1689.     disk_buffer[4]>='0' && disk_buffer[4]<='9' &&
  1690.     disk_buffer[5]>='a' && disk_buffer[5]<='z') return true;
  1691. return false;
  1692. /*    since a gif file has an internal signature, it's better to rely on it
  1693. than to look at the name...
  1694. short l;
  1695. l=strlen(tarh.name);
  1696. return (l >4 && !ci_strcmp(&tarh.name[l-4],".gif" );
  1697. */
  1698. }
  1699.  
  1700. void print_type_creator(t,c)
  1701. OSType t,c;
  1702. {
  1703. /* sorry, my printf doesn't accept %.4s */
  1704. printf(in_Italia?"tipo=\'":"type=\'");
  1705. print_chars(&t,4);
  1706. printf(in_Italia?"\' creatore=\'":"\' creator=\'");
  1707. print_chars(&c,4);
  1708. printf("\'");
  1709. }
  1710.  
  1711. void print_one_date(cdate,message)
  1712. long cdate;
  1713. char*message;
  1714. {
  1715.     char p[20];
  1716.     printf("%s",message);
  1717.     IUDateString(cdate,abbrevDate,p);
  1718.     printf("%P ",p);
  1719.     IUTimeString(cdate,true,p);
  1720.     printf("%P",p);
  1721. }
  1722.  
  1723.  
  1724.  
  1725. void cancella_file_aperto(ioRefNum)
  1726. short ioRefNum;
  1727. {
  1728. OSErr i;
  1729. get_openfile_location(ioRefNum);
  1730. PBCloseSync(&pb);
  1731. pb.fileParam.ioNamePtr=mac_file_name;
  1732. pb.fileParam.ioVRefNum=openfile_vrefnum;
  1733. pb.fileParam.ioDirID=openfile_dirID;
  1734. i=PBHDeleteSync(&pb);
  1735. /*printf("delete=%d\n",i);*/
  1736. }
  1737.  
  1738. short crea_e_controlla(tempattrib)
  1739. /* crea un file ma fa anche qualche controllo...;
  1740. ritorna come create_file
  1741. -- creates a file and does some checking; returns as create_file
  1742. */
  1743. Boolean tempattrib;
  1744. {
  1745. char copia[100];
  1746. short i;
  1747.  
  1748. mcopy(copia,tarh.name,100);
  1749. for(;;){
  1750.     if( create_file(tarh.name,fsWrPerm,tempattrib)) return 1;    /* Cancel... */
  1751.     
  1752.     i=controlla_spazio(macbinh.dflen,macbinh.rflen);
  1753.     if(i==1){    /* Skip */
  1754.         delete_out_file();    /* it exists but it's currently of 0 size */
  1755.         return 1;
  1756.         }
  1757.     if(i==2){    /* continue elsewhere */
  1758.         delete_out_file();
  1759.         /* restore the name, in case it was changed (e.g. if the file existed...) */
  1760.         mcopy(tarh.name,copia,100);
  1761.         /* and retry... */
  1762.         }
  1763.     else{
  1764.         if(macbinh.finfo.fdFlags&0x4000){    /* bit "invisible" */
  1765.             if(my_semimodal_dialog(147,titoli,2,
  1766.                 in_Italia?"\pFile invisibile: lo rendo visibile ?":
  1767.                 "\pInvisible file: make it visible ?",PNS,PNS)==1)
  1768.                 macbinh.finfo.fdFlags &= ~0x4000;
  1769.             }
  1770.         return 0;
  1771.         }
  1772.     }
  1773. }
  1774.  
  1775.  
  1776. short controlla_spazio(dlen,rlen)
  1777. long dlen,rlen;
  1778. /* checks that the destination volume has enough free space;
  1779. returns 0 if OK, 1 if not enough space and the user canceled
  1780. the operation, 2 if not enough space and the user selected another
  1781. volume for continuing
  1782. */
  1783. {
  1784. long l;
  1785. short vrefnum;
  1786. Boolean prima_volta=true;
  1787. short i;
  1788.  
  1789. for(;;){
  1790.     if(pb.fileParam.ioVRefNum)
  1791.         vrefnum=pb.fileParam.ioVRefNum;
  1792.     else{
  1793.         volumeParam param;
  1794.         char buffer[50];
  1795.         param.ioNamePtr=buffer;    /* or NULL, but what happens if some system bug
  1796.                             (or a bad INIT) does not check for NULLs ? */
  1797.         if(PBGetVolSync (¶m) !=noErr) return;
  1798.         vrefnum=param.ioVRefNum;
  1799.         }
  1800.     if(GetVInfo (0,NULL,&vrefnum,&l)!=noErr)
  1801.         return 0;        /* the error could be not fatal, it's better to hope that
  1802.                         anything is OK, this routine is only a check to prevent
  1803.                         some errors but suntar still works without checking for
  1804.                         space... */
  1805.     /*printf("l=%ld\n",l);*/
  1806.     if( ((dlen+511)&~511L) + ((rlen+511)&~511L) <= l )
  1807.         return 0;    /* space is enough */
  1808.     else{
  1809.         if(!prima_volta){
  1810.             if(my_semimodal_dialog(147,titoli,2,
  1811.                 in_Italia?"\pSpazio ancora insufficiente,\rproseguo comunque ?":
  1812.                 "\pSpace is still insufficient,\rcontinue anyway ?",PNS,PNS)==1)
  1813.                 return 0;
  1814. /*            else continue */
  1815.             }
  1816.         do{
  1817.             i=semimodalDialog(141,NULL,NULL,titoli_full,3,
  1818.                in_Italia?"\pSpazio su disco insufficiente: puoi voler cancellare\r\
  1819. qualcosa prima di cliccare su un bottone\roppure puoi abortire il comando":
  1820. "\pInsufficient space on destination volume: you\r\
  1821. might wish to delete something before clicking a\r\
  1822. button or you may abort the current command",
  1823.                NULL,NULL,teJustCenter,true,NULL);
  1824.             if(i==2){
  1825.                    /* continue elsewhere */
  1826.                 select_directory();
  1827.                 cancella_file_aperto(pb.ioParam.ioRefNum);
  1828.                 if(reply.good) return 2;
  1829.                 }
  1830.             else if(i==3)    /* skip */
  1831.                 return 1;
  1832.             else{
  1833.                 /* continue here: maybe the user deleted some files */
  1834.                 prima_volta=false;
  1835.                 }
  1836.             }
  1837.         while(i==2);    /* if I'm here, it was cancelled */
  1838.         }
  1839.     }
  1840. }
  1841.  
  1842.  
  1843.  
  1844. static short gestisci_nome_doppio(fname,name,fpb,duplicate)
  1845. /* handle a duplicate name error */
  1846. char *fname,*name;
  1847. register FileParam *fpb;
  1848. Boolean duplicate;
  1849. {
  1850. short err,i,l=strlen(fname);
  1851. WDPBRec param;
  1852.  
  1853. settori_passati=0;
  1854. beep_in_foreground();
  1855. /*if(fase==hack_reading){
  1856.     error_message("File already existing !\n");
  1857.     }
  1858. */
  1859. /* ci sono due modi di procurarsi le informazioni da mettere nelle due variabili 
  1860. che dicono dove lo standard file deve posizionarsi inizialmente:
  1861. 1) come nel programma Apple, creare una WD con PBOpenWD e poi fare PBGetWDInfo
  1862. 2) non creare alcuna WD, ma allora bisogna usare PBGetCatInfo per avere il DirID
  1863.    e PBGetWDInfo (sulla WD preesistente...) per avere il vRefNum del volume
  1864.    (cioè, della root)
  1865. per ora seguo il metodo 1, che funziona, ma quando avrò tempo preferirei passare al 2
  1866. -- I must oblige SFPutFile to show the folder where the file had to go, and that's
  1867. done by setting two low memory variables. But I must get the information in the
  1868. right format, and the simplest way to do that requires the creation of a working
  1869. directory (the other way looks even easier, but currently it does not work, at least
  1870. not always)
  1871. */
  1872.  
  1873. for(i=l-1;i>=0 && fname[i]!=':';i--)
  1874.     ;
  1875. #if 1
  1876. /* ora i è -1 o punta ad un ':' */
  1877. if(i<=0){        /* un : in testa non conta... */
  1878.     err=GetVol (name,¶m.ioVRefNum);
  1879.     /* name[0]=0; */
  1880.     }
  1881. else{
  1882.     mcopy(&name[1],fname,i+1);    /* così tronco al : (che resta compreso)...*/
  1883.     name[0]=i+1;
  1884.  
  1885.  
  1886. #ifdef USA_CURRVREFN
  1887.     param.ioVRefNum=curr_vrefnum;
  1888. #else
  1889.     param.ioVRefNum=0;
  1890. #endif
  1891.     }
  1892.     param.ioNamePtr=(unsigned char*)name;
  1893.     param.ioWDProcID=signature;
  1894.     param.ioWDDirID=0;
  1895.     err=PBOpenWDSync(¶m);        /* ho bisogno di una WD perché doForceDirectory
  1896.                                 è fatta a quel modo... */
  1897.     doForceDirectory(¶m);
  1898.     register_WD(param.ioVRefNum);
  1899.  
  1900. #else
  1901. /* that's the second way: in this form it's worse, but, damn it, why should I be
  1902. obliged to do two calls to get both the dirID and the root vRefNum ? */
  1903.  
  1904. /* se mi decido per questo, togliere doForceDirectory da StdFile.c ! */
  1905. /*printf("giusti = %d %ld \n",-SFSaveDisk,CurDirStore);*/
  1906. {CInfoPBRec cinfo;
  1907.  
  1908. printf("fname=%s, name=%P\n",fname,name);
  1909.  
  1910. cinfo.dirInfo.ioNamePtr= (unsigned char*)name;
  1911. cinfo.dirInfo.ioVRefNum=curr_vrefnum;
  1912. cinfo.dirInfo.ioFDirIndex=0;
  1913. cinfo.dirInfo.ioDrDirID=0;
  1914. PBGetCatInfoSync(&cinfo);        /* get the dirID */
  1915.  
  1916. /*printf("result= %d attr=%x\n",cinfo.dirInfo.ioResult,cinfo.dirInfo.ioFlAttrib);
  1917. printf("cose che vedo =%d %ld %d\n",cinfo.dirInfo.ioVRefNum,cinfo.dirInfo.ioDrDirID,
  1918.     cinfo.dirInfo.ioFRefNum);*/
  1919. /*cinfo.dirInfo.ioDrDirID contiene il DirId giusto, ma il vRefNum giusto
  1920. non sta in nessun campo !*/
  1921.     param.ioNamePtr = NULL;
  1922.     param.ioVRefNum = 0;
  1923.     param.ioWDIndex = 0;
  1924.     param.ioWDProcID = 0;
  1925.  
  1926.     PBGetWDInfoSync(¶m);        /* get the vrefnum */
  1927. /* ioVRefNum è quello che voglio, ma ovviamente non avendogli dato il path da lì
  1928. non posso avere alcun DirID, e anche a dare il path sembra che non si ottenga */
  1929. /*printf("stavolta ho %d %ld\n",param.ioVRefNum, param.ioWDDirID);*/
  1930.  
  1931.     CurDirStore = cinfo.dirInfo.ioDrParID  or cinfo.dirInfo.ioDrDirID ???????;
  1932.     SFSaveDisk = -param.ioVRefNum;
  1933. }
  1934. #endif
  1935. /*printf("settato %d %ld\n",SFSaveDisk,CurDirStore);*/
  1936.  
  1937. my_c2pstr(&fname[i+1]);
  1938.  
  1939. while( SFPut_con_pausa(&fname[i+1],duplicate?
  1940.     (in_Italia?"\pIl file esiste già,\rsalvalo come:":
  1941.     "\pThe file is already existing,\rsave as:") :
  1942.     "\pFile could not be created,\rsave as:")){
  1943.     handle_pause();
  1944.     accept_abort_command();
  1945.     }
  1946. if(!reply.good) return 1;
  1947.  
  1948.     fpb->ioNamePtr = reply.fName;
  1949.     fpb->ioVRefNum = reply.vRefNum;
  1950.     fpb->ioFVersNum = 0;
  1951.     err=PBCreateSync(fpb) ;
  1952.     pStrcpy(fname,reply.fName);        /* devo salvarlo prima se no lo perdo */
  1953.     if(err==dupFNErr){
  1954.         if(open_overwrite(reply.fName,reply.vRefNum,&(fpb->ioFRefNum))==noErr)    /* ok il 
  1955.                 codice che dice che esiste, siamo dopo un SFPutFile, ma bisogna 
  1956.                 troncare il file... */
  1957.             FSClose(fpb->ioFRefNum);
  1958.         }
  1959.  
  1960.     else if(err!=noErr)
  1961.         pbsyserr(fpb);
  1962.  
  1963.     my_p2cstr(fname);
  1964.     fpb->ioVRefNum = reply.vRefNum;
  1965.     fpb->ioFVersNum = 0;
  1966.     fpb->ioFDirIndex = 0;
  1967.     return 0;
  1968. }
  1969.  
  1970. static void skip_macbinII(size)
  1971. short size;
  1972. {
  1973. while(size>0){
  1974.     if(readblock(&tarh,128)) raise_error();
  1975.     size-=128;
  1976.     }
  1977. }
  1978.  
  1979.  
  1980. void get_openfile_location(ioRefNum)
  1981. short ioRefNum;
  1982. {
  1983. /* get the current name and location of the file, so that it may be
  1984. reopened even if the user has moved or renamed it */
  1985.  
  1986. FCBPBRec param;
  1987.  
  1988. fillmem(¶m,0,sizeof(param));
  1989. param.ioVRefNum=0;
  1990. param.ioRefNum=ioRefNum;
  1991. param.ioFCBIndx=0;
  1992.  
  1993. param.ioNamePtr=mac_file_name;
  1994. if((err_code=PBGetFCBInfoSync(¶m))==noErr){
  1995.     openfile_vrefnum=param.ioFCBVRefNum;
  1996.     openfile_dirID=param.ioFCBParID;
  1997.     /*pStrcpy(mac_file_name,param.ioNamePtr);*/
  1998.     }
  1999. else
  2000.     openfile_dirID=0;
  2001. /*
  2002. printf("err=%d(%d) ioV=%d ioR=%d volRN=%d dirID=%ld name=%lx:%P\n",
  2003. err_code,param.ioResult,param.ioVRefNum,param.ioRefNum,param.ioFCBVRefNum,param.ioFCBParID,
  2004. param.ioNamePtr,param.ioNamePtr);
  2005. */
  2006.  
  2007. }
  2008.  
  2009. static void print_containing()
  2010. {
  2011. register short i;
  2012. i=0;
  2013. printf(in_Italia ? "Contenente " : "Containing ");
  2014. while(i<macbinh.nlen){
  2015.     if(macbinh.name[i]=='\r') /* it happens for icon files, and if you do a MacBinary
  2016.                         write of a folder the icon file is saved */
  2017.         put_char(19);        /* diamond, in most fonts it's missing but that's OK
  2018.                         for this purpose */
  2019.     else
  2020.         put_char(macbinh.name[i]);
  2021.     i++;
  2022.     }
  2023. printf(" (data %ld+res %ld bytes)", macbinh.dflen, macbinh.rflen);
  2024. }
  2025.     
  2026.  
  2027. /************* end of routines by Speranza **************************/
  2028.  
  2029. /************* Routines obtained by modifying ones by Zacharias **********
  2030. (that is, modifying their interface and purpose and not only their code)
  2031.  **********************************************************************/
  2032.  
  2033.  
  2034. /********************* hqx *******************************/
  2035.  
  2036. void untar_hqx (fsize)
  2037.   long fsize;
  2038. {
  2039. register char *cp;
  2040. jmp_buf savebuf;
  2041. short i;
  2042.  
  2043. hqx_length=fsize;
  2044. mcopy(&savebuf,&main_loop,sizeof(jmp_buf));
  2045. if((i=setjmp(main_loop))<0 ){
  2046.     mcopy(&main_loop,&savebuf,sizeof(jmp_buf));
  2047.     if(i==-2)        /* raise_hqx_error... */
  2048.         return;
  2049.     raise_error();
  2050.     }
  2051.  
  2052. if( hqx_header() ){            /* con risultati in macbinh
  2053.                             -- results in macbinh */
  2054.     mcopy(&main_loop,&savebuf,sizeof(jmp_buf));
  2055.     return;
  2056.     }
  2057.  
  2058. for(cp = tarh.name+strlen(tarh.name); cp != tarh.name && cp[-1] != ':'; --cp);
  2059. mcopy(cp, macbinh.name, macbinh.nlen);
  2060. cp[macbinh.nlen] = '\0';
  2061.  
  2062. disable_autoflush(1);
  2063. if(expert_mode&&file_aperto<=ff_tarbar) printf(s_spazi);    /*per allinearsi col [sector xxxx] stampato
  2064.                 presumibilmente alla riga prima
  2065.                 -- to align with the [sector xxxx] printed in the previous line */
  2066. print_containing();
  2067. if(fase==hack_listing){
  2068.     printf("  ");
  2069.     print_type_creator(macbinh.finfo.fdType,macbinh.finfo.fdCreator);
  2070.     }
  2071. printf("\n");
  2072. if(macbinh.dflen+macbinh.rflen>=FLUSH_MIN_SIZE) flush_console();    /* somebody
  2073.     complained about the slowness of the operations with many small files, and
  2074.     buffering the printing to the console may speed up things up to 40%, but I
  2075.     can't leave the console unflushed during a long file... */
  2076.  
  2077. filecreator=filetype='????';
  2078.  
  2079.  
  2080. if(!listonly && ! crea_e_controlla(true) ){
  2081.  
  2082.     write_hqx_fork(512,macbinh.dflen);
  2083.  
  2084.     pb.ioParam.ioVersNum = 0;
  2085.     pb.ioParam.ioPermssn = fsWrPerm;
  2086.     pb.ioParam.ioMisc = 0;
  2087.     if((pb.fileParam.ioDirID=openfile_dirID)!=0){
  2088.         pb.ioParam.ioVRefNum=openfile_vrefnum;
  2089.         pb.ioParam.ioNamePtr=mac_file_name;
  2090.         }
  2091.     if( PBHOpenRFSync(&pb)) pbsyserr(&pb);
  2092.  
  2093.     devo_chiudere_out=true;
  2094.  
  2095.     write_hqx_fork(512,macbinh.rflen);
  2096.  
  2097.     set_binhex();
  2098.     if(hqx_length > 16)    /* tanto per dare un valore... 
  2099.                     -- well, due to multiple buffering of data that variable
  2100.                     does NOT hold the number of remaining chars, at least if
  2101.                     those chars are before the final ':' (the buffering does
  2102.                     not go past that ':'); on the other hand I don't check for 
  2103.                     the presence of that ':', and I've read that
  2104.                     "Some old programs produced an extra exclamation mark (!) 
  2105.                     immediately before the final colon", hence I don't want to
  2106.                     check that no extra chars are present.
  2107.                     */
  2108.         printf(in_Italia ? "%ld caratteri dopo i dati Binhex sono stati ignorati\n" :
  2109.                 "%ld characters follow BinHex data: ignored\n", hqx_length);
  2110.     }
  2111. hqx_end_of_file();
  2112. mcopy(&main_loop,&savebuf,sizeof(jmp_buf));
  2113. }
  2114.  
  2115. void write_hqx_fork(chunk_size,size)
  2116.   short chunk_size;
  2117.   long size;
  2118. {
  2119. short bytes_to_read;
  2120.  
  2121. reinit_hd_buffering();
  2122. current_crc=0;
  2123. while (size) {
  2124.     bytes_to_read= chunk_size;
  2125.     if(bytes_to_read>size) bytes_to_read=size;
  2126.     read_hqx(&tarh,bytes_to_read);
  2127.     size -= bytes_to_read;
  2128.     if(write_hd((char*) &tarh, bytes_to_read) ) pbsyserr(&pb);
  2129.     }
  2130. if(flush_hd_buffer()) pbsyserr(&pb);
  2131. get_openfile_location(pb.ioParam.ioRefNum);
  2132. PBCloseSync(&pb);
  2133. devo_chiudere_out=false;
  2134. check_CRC();
  2135. }
  2136.  
  2137. void write_pit_fork(chunk_size,size)
  2138.   short chunk_size;
  2139.   long size;
  2140. {
  2141. short bytes_to_read;
  2142.  
  2143. reinit_hd_buffering();
  2144.  
  2145. while (size) {
  2146.     bytes_to_read= chunk_size;
  2147.     if(bytes_to_read>size) bytes_to_read=size;
  2148.     get_pit_bytes(&tarh,bytes_to_read);
  2149.  
  2150.     size -= bytes_to_read;
  2151.     if(write_hd((char*) &tarh, bytes_to_read)) pbsyserr(&pb);
  2152.     }
  2153. if(flush_hd_buffer()) pbsyserr(&pb);
  2154. get_openfile_location(pb.ioParam.ioRefNum);
  2155. PBCloseSync(&pb);
  2156. devo_chiudere_out=false;
  2157. }
  2158.  
  2159.  
  2160. void set_binhex ()
  2161. /* set the file informations from the BinHex header, almost identical to setmacbin */
  2162. {
  2163. FileParam fpb;
  2164. fpb.ioFVersNum = 0;
  2165. fpb.ioFDirIndex = 0;
  2166.  
  2167. if((fpb.ioDirID=openfile_dirID)!=0){
  2168.     fpb.ioVRefNum=openfile_vrefnum;
  2169.     fpb.ioNamePtr=mac_file_name;
  2170.     }
  2171. else{
  2172.     fpb.ioVRefNum=pb.fileParam.ioVRefNum;
  2173.     fpb.ioNamePtr=pb.fileParam.ioNamePtr;
  2174.     }
  2175.  
  2176. if (PBHGetFInfoSync(&fpb)) pbsyserr(&fpb);
  2177.  
  2178. clear_unused_fields();
  2179. mcopy(&fpb.ioFlFndrInfo, &macbinh.finfo, 10); /* type,creator e flags ma non il resto*/
  2180. if(file_aperto==ff_binhex){
  2181.     fpb.ioFlCrDat=macbinh.cdate;
  2182.     fpb.ioFlMdDat=macbinh.mdate;
  2183.     }
  2184. else if(file_date!=-1)
  2185.         fpb.ioFlCrDat = fpb.ioFlMdDat = file_date + UNIXTIME;
  2186. fpb.ioDirID=openfile_dirID;    /* PBHSetFInfo writes the FlNum return value in that field ! */
  2187. if (PBHSetFInfoSync(&fpb)) pbsyserr(&fpb);
  2188. }
  2189.  
  2190.  
  2191. short untar_checksum(buffer,do_error,verbose)
  2192. register unsigned char *buffer;
  2193. short do_error;
  2194. Boolean verbose;
  2195. {
  2196. register short i;
  2197. register long chksum;
  2198. long hchksum;
  2199. #define tar_chksum_offset 148 /* (tarh.checksum-(char*)&tarh) */
  2200. hchksum = untar_number(((tarh_type*)buffer)->chksum,do_error);
  2201. if(hchksum==-1){
  2202.     if(verbose) printf("Empty header checksum\n");
  2203.     return -2;        /* testata non tar */
  2204.     }
  2205. chksum= ' ' * 8;    /* nel calcolo del checksum, il campo checksum era sostituito
  2206.                     da spazi */
  2207. for (i=0; i < tar_chksum_offset; ++i)
  2208.     chksum += (unsigned char)*buffer++;
  2209. for (i+=8,buffer+=8; i < sizeof(tarh); ++i)
  2210.     chksum += (unsigned char)*buffer++;
  2211.  
  2212. if (chksum == hchksum) return 0;    /* tutto OK */
  2213. if(verbose){
  2214.     printf("Bad header checksum ");
  2215.     if(expert_mode){
  2216.         if(((tarh_type*)disk_buffer)->linkflag!='V')
  2217.             if(print_if_string("(got %s expected ",((tarh_type*)disk_buffer)->chksum,8))
  2218.                 printf("%lo)",chksum);
  2219.         }
  2220.     printf("\n");
  2221.     }
  2222. return -1;
  2223. }
  2224.  
  2225.  
  2226. short chkmacbin (fsize,relax_test)
  2227. /* tests whether the file is MacBinary */
  2228.   long fsize;
  2229.   short relax_test;
  2230. {
  2231.   char buf[128];
  2232.  
  2233.  
  2234.   if (fsize == 0) return 0;
  2235.   if (readblock(buf,128))     /* devo leggerlo comunque, per uniformità */
  2236.       raise_error();
  2237.   if (fsize < 128){
  2238.     unget_block();
  2239.     return 0;
  2240.     }
  2241.   mcopy(&macbinh, &buf[1], sizeof(macbinh));
  2242.  
  2243. /* in the MacBinary format, the data and resource forks should occupy an
  2244. integer number of 128 bytes blocks (the size of XMODEM blocks): however, 
  2245. some programs save space by not extending the two forks, hence I must
  2246. accept both standard ad "compact" formats
  2247. */
  2248.  
  2249. if (buf[0] == 0 && macbinh.zero == 0 && macbinh.nlen < 64 && macbinh.nlen > 0 )
  2250.     if(macbinh.dflen >= 0 && macbinh.rflen >= 0 ){
  2251.         short i=isMacBin2(buf);
  2252.         long expected_length_compact=macbinh.dflen +macbinh.rflen + 128L;
  2253.         long expected_length_standard=macbinsz(macbinh.dflen) + macbinsz(macbinh.rflen) + 128L;
  2254.         if( (MacBinaryII=i>0)){
  2255. /* The MacBinary || standard defines fields for the sizes of extra header info
  2256. and of comment:
  2257. >  Offset 099-Word, length of Get Info comment to be sent after the resource
  2258. >             fork (if implemented).
  2259. > *Offset 120-Word, Length of a secondary header.  If this is non-zero,
  2260. >             Skip this many bytes (rounded up to the next multiple of 128)
  2261. >             This is for future expansion only, when sending files with
  2262. >             MacBinary, this word should be zero.
  2263.  we've never seen files using those fields, nor versions of MacbinaryII
  2264.  bigger than 129, but it would not be honest to declare that suntar is
  2265.  MacBinaryII compatible without supporting them
  2266. */
  2267.             mcopy(&mbIIsec_head_len,&macbinh.headlen[0],2);
  2268.             mbIIsec_head_len = macbinsz(mbIIsec_head_len);
  2269.             expected_length_standard += macbinh.gilen + mbIIsec_head_len;
  2270.             /* I believe that a MBII file can't be "compact", and surely it can't 
  2271.             be compact and have comment info or secondary header */
  2272.             }
  2273.         if(relax_test ||
  2274.             (fsize==expected_length_compact||fsize==expected_length_standard) &&
  2275.             i>=0 ){
  2276.             notTrueMacBinary = fsize<expected_length_standard;
  2277.             if(relax_test==ff_c_macbin&&fsize<expected_length_standard)
  2278.                 notTrueMacBinary=true;
  2279.  
  2280.             if( MacBinaryII )
  2281.                 macbinh.finfo.fdFlags = macbinh.finfo.fdFlags&0xFF00 |
  2282.                     (unsigned char) macbinh.extra_fflags;
  2283.             /* else
  2284.                 macbinh.finfo.fdFlags = macbinh.finfo.fdFlags&0xFF00; NO:
  2285. The first MacBinary standard did not store bits 7-0, stating that
  2286. the byte following bits 15-8 should be zeroed. But mtar did not zero it, and maybe
  2287. it's the same for other programs (but NOT for BinHex5.0), anyway suntar does not check
  2288. for them to be zero, and in a MacBinary (not MacBinary II) files which has a nonzero 
  2289. value in that byte it believes that it's containing the correct values of bits 0-7.
  2290. */
  2291.               return 1;
  2292.               }
  2293.         }
  2294.     unget_block();
  2295.     return 0;
  2296. }
  2297.  
  2298. void setdata ()
  2299. /* set modification date = creation date */
  2300. {
  2301. FileParam fpb;
  2302. fpb.ioFVersNum = 0;
  2303. fpb.ioFDirIndex = 0;
  2304.  
  2305. if((fpb.ioDirID=openfile_dirID)!=0){
  2306.     fpb.ioVRefNum=openfile_vrefnum;
  2307.     fpb.ioNamePtr=mac_file_name;
  2308.     }
  2309. else{
  2310.     fpb.ioVRefNum=pb.fileParam.ioVRefNum;
  2311.     fpb.ioNamePtr=pb.fileParam.ioNamePtr;
  2312.     }
  2313. if (PBHGetFInfoSync(&fpb)==noErr){    /* not to be able to set the date is NOT a big error */
  2314.     fpb.ioFlMdDat = fpb.ioFlCrDat;
  2315.     fpb.ioDirID=openfile_dirID;
  2316.     PBHSetFInfoSync(&fpb);
  2317.     }
  2318. }
  2319.  
  2320. /******* end of routines by Gail Zacharias, rewritten by Speranza ********/
  2321.  
  2322. /***************** start of routines by Gail Zacharias **********/
  2323.  
  2324.  
  2325. void untar ()
  2326. {
  2327.  
  2328. long exp_check;
  2329. short i;
  2330.  
  2331.     disable_autoflush(1);
  2332.     if(expert_mode) print_sector_n(sect_n);
  2333.     sect_n++;
  2334.     more_in_bytes=0;    /* forse non necessario, ma prudente */
  2335.  
  2336.     mcopy(&tarh,&disk_buffer,sizeof(tarh));
  2337.     if ( (i=untar_checksum(&disk_buffer[0],1,true)) != 0 ){
  2338.         if(i==-2 || !ignore_errors) raise_error();
  2339.         if(i==-1) printf(s_spazi);
  2340.         }
  2341.     copia_ultimo_header(disk_buffer,sect_n);    /* sect_n è già stato incrementato */
  2342.     last_offset=0;        /* l'offset è 0 perché non è un header 'M' */
  2343.  
  2344.     file_date= untar_number(&tarh.mtime,false);
  2345.  
  2346.     switch (tarh.linkflag) {
  2347.     case '\0': case '0': case '7':
  2348. is_file:    
  2349.         if (tarh.name[strlen(tarh.name)-1] == '/')
  2350.             untar_directory();
  2351.         else
  2352.             untar_file(untar_number(tarh.size,1));
  2353.         break;
  2354.     case '1': case '2':
  2355.         untar_link();
  2356.         break;
  2357.     case '5':
  2358.         untar_directory();
  2359.         break;
  2360.     case 'M':
  2361.         if(untar_number(&tarh.offset,-1)==0) goto is_file;        /* the file header
  2362.             was in the last sector of previous disk, hence this continuation
  2363.             header is followed by the whole contents of the file, so it may
  2364.             be extracted starting from here: all informations are available... */
  2365.         /* else continue */
  2366.     case 'V':
  2367.         printf("Bad use of GNU extensions\n");
  2368.         raise_error();
  2369.         break;
  2370.     default:
  2371.         printf("Unknown header type (octal %o)\n", tarh.linkflag);
  2372.         raise_error();
  2373.     }
  2374. }
  2375.  
  2376.  
  2377. void untar_file (fsize)
  2378. long fsize;
  2379. {
  2380.   short nLF;
  2381.   short isText;
  2382.   short isBinHex;
  2383.   Boolean is_gif=false;
  2384.   long cdate=untar_number(bar_archive?((barh_type*)disk_buffer)->mtime:
  2385.         ((tarh_type*)disk_buffer)->mtime,-1);
  2386.     if(listonly!=2) printf("File %s", tarh.name);    /* 2 means Get File Info, which has
  2387.                 already printed the file name and size */
  2388.     if(!bar_archive){
  2389.         next_header_for_AIX = sect_n + ((fsize+511)>>9);
  2390.         if(next_header_for_AIX<sectors_on_floppy)
  2391.             next_header_for_AIX=-1;
  2392.         else
  2393.             next_header_for_AIX-=sectors_on_floppy;
  2394.         }
  2395.     if(sect_n==sectors_on_floppy){
  2396.         if(fase==hack_listing){
  2397.             if(file_aperto)
  2398.                 printf(UNEXP);
  2399.             else
  2400.                 printf(" (%ld bytes, on next disk)\n",fsize);
  2401.             /* for expert list of AIX archives, I must let sect_n point to next
  2402.             file header... */
  2403.             enable_autoflush();
  2404.             longjmp(main_loop,-1);
  2405.             }
  2406.         else
  2407.             start_of_line();    /* ci saranno i messaggi di cambio disco...
  2408.                                 --some messages are arriving... */
  2409.         enable_autoflush();
  2410.         }
  2411.     if ( file_aperto==ff_macbin || file_aperto<=ff_tarbar && chkmacbin(fsize,0)){
  2412.         /*printf(" ");
  2413.         if(fase==hack_listing)*/
  2414.         if(listonly!=2) printf(" (%ld bytes) ",fsize);
  2415.         if(notTrueMacBinary) printf("compact ");
  2416.         printf("MacBinary");
  2417.         if(MacBinaryII) printf(" II");
  2418.         printf("\n");
  2419.         if(expert_mode&&file_aperto<=ff_tarbar) printf(s_spazi);
  2420.         print_containing();
  2421.         if(fase==hack_listing){
  2422.             printf("\n%s",s_spazi);
  2423.             print_type_creator(macbinh.finfo.fdType,macbinh.finfo.fdCreator);
  2424.             if(cdate!=-1) print_one_date(cdate+UNIXTIME,in_Italia?"  creato ":"  created ");    /* di solito in expert mode non
  2425.                     bado alla lingua, ma poi stampo una stringa del toolbox che lo fa...*/
  2426.             }
  2427.         printf("\n");
  2428.         if(macbinh.dflen+macbinh.rflen>=FLUSH_MIN_SIZE) flush_console();
  2429.  
  2430.         check_confirmation();    /* se ora andassi in non_convertire, nessun problema... */
  2431.         if(non_convertire&&file_aperto<=ff_tarbar){
  2432.               unget_block();    /* i 128 bytes di intestazione... */
  2433.             filetype='TEXT';
  2434.             filecreator='BnHq';        /* il creator di BinHex 5.0 */
  2435.             untar_data(fsize);
  2436.               }
  2437.           else{
  2438.             unix_to_mac(tarh.name);
  2439.             untar_macbin(fsize);
  2440.             }
  2441.         }
  2442.     else{
  2443.         if(listonly!=2) printf(" (%ld bytes)",fsize);    /* queste scritte devono stare prima della
  2444.                     check_confirmation, ma del resto i test sulle conversioni vanno dopo
  2445.                     e questo complica un po' le cose */
  2446.         if(file_aperto<=ff_tarbar)
  2447.             isBinHex= fsize>=20 ? is_hqx_name() : 0;
  2448.         else
  2449.             isBinHex=file_aperto==ff_binhex;
  2450.         if(isBinHex){
  2451.             printf(in_Italia?" testo BinHex":" BinHex text");
  2452.             binary=0;    /* per il caso poi non vada convertito */
  2453.             }
  2454.         else{
  2455.             if(file_aperto<=ff_tarbar){
  2456.                   isText=isASCII(fsize,&nLF); /* grazie a chkmacbin, disk_buffer è pieno... */
  2457.                     binary= ! (isText>0 && nLF>0);
  2458.                     }
  2459.             else{
  2460.                   isText= file_aperto==ff_ASCII;    /* I'm not here in that case, but
  2461.                           who knows what may happen in the future... */
  2462.                   binary=false;
  2463.                   }
  2464.  
  2465.             if (isText>0 && !binary)
  2466.                 printf(in_Italia?" testo ASCII con LF":" ASCII text using LF");
  2467.             else if(isText>0)
  2468.                 printf(in_Italia?" testo ASCII":" ASCII text");
  2469.             else if((is_gif=is_gif_file(fsize)))
  2470.                 printf(" CompuServe GIF");
  2471.             }
  2472.         if(fase==hack_listing)
  2473.             if(cdate!=-1) print_one_date(cdate+UNIXTIME,in_Italia?"  creato ":"  created ");
  2474.  
  2475.         printf("\n");
  2476.         if(fsize>=FLUSH_MIN_SIZE) flush_console();
  2477.  
  2478.         check_confirmation();    /* durante il quale posso anche cambiare preferences */
  2479.         unix_to_mac(tarh.name);
  2480.  
  2481.         if( !(disable_binhex&1) && isBinHex==1 && 
  2482.             !(non_convertire&&file_aperto<=ff_tarbar && !listonly) ){
  2483.               untar_hqx(fsize);
  2484.               }
  2485.         else{
  2486.               if(is_gif ){
  2487.                   filecreator= gif_creator;
  2488.                   filetype='GIFf';
  2489.                   }
  2490.               else{
  2491.                   filecreator= (isText>0||isBinHex) ? text_creator : '????';
  2492.                   filetype= (isText||isBinHex) ? 'TEXT' : '????';
  2493.                   }
  2494.               untar_data(fsize);
  2495.           }
  2496.     }
  2497. }
  2498.  
  2499.  
  2500. void untar_data (fsize)
  2501.   long fsize;
  2502. {
  2503.  
  2504.     macbinh.dflen=fsize;        /* crea_e_controlla expects some data here... */
  2505.     macbinh.rflen=0;
  2506.     macbinh.finfo.fdFlags=0;
  2507.     if(!listonly && ! crea_e_controlla(false) ){
  2508.  
  2509.         pb.ioParam.ioReqCount = sizeof(tarh);
  2510.         notTrueMacBinary=true;    /* writefork tests it... in practice its value is
  2511.             irrelevant, since extra bytes in the last sector are skipped anyway */
  2512.         writefork(512, fsize, binary || non_convertire&&file_aperto<=ff_tarbar);
  2513.         if(save_modi_date) setdata();
  2514.         }
  2515.     else
  2516.         skip_file(fsize);
  2517. }
  2518.  
  2519. void untar_macbin (fsize)
  2520.   long fsize;
  2521. {
  2522. register char *cp;
  2523.  
  2524. for(cp = tarh.name+strlen(tarh.name); cp != tarh.name && cp[-1] != ':'; --cp);
  2525. mcopy(cp, macbinh.name, macbinh.nlen);
  2526. cp[macbinh.nlen] = '\0';
  2527.  
  2528. filecreator=filetype='????';    /* temporaneamente, ma in caso di errore resta così */
  2529.  
  2530. if(!listonly && ! crea_e_controlla(true) ){
  2531.     if(MacBinaryII) skip_macbinII(mbIIsec_head_len);    /* secondary header... */
  2532.     writefork(128,macbinh.dflen, 1);
  2533.     pb.ioParam.ioVersNum = 0;
  2534.     pb.ioParam.ioPermssn = fsWrPerm;
  2535.     pb.ioParam.ioMisc = 0;
  2536.     if((pb.fileParam.ioDirID=openfile_dirID)!=0){
  2537.         pb.ioParam.ioVRefNum=openfile_vrefnum;
  2538.         pb.ioParam.ioNamePtr=mac_file_name;
  2539.         }
  2540.     if( PBHOpenRFSync(&pb)) pbsyserr(&pb);
  2541.     devo_chiudere_out=true;
  2542.     pb.ioParam.ioReqCount = 128;
  2543.     writefork(128,macbinh.rflen, 1);
  2544.     if(MacBinaryII) skip_macbinII(macbinh.gilen);        /* comment */
  2545.     setmacbin();
  2546.  
  2547.     end_of_file();
  2548.     }
  2549. else
  2550.     skip_file(fsize);
  2551. }
  2552.  
  2553. void writefork(chunk_size, size, binp)
  2554. short chunk_size;
  2555. long size;
  2556. Boolean binp;
  2557. {
  2558.     short bytes_to_read;
  2559.  
  2560.     reinit_hd_buffering();
  2561.  
  2562.     while (size) {
  2563.         bytes_to_read= chunk_size;
  2564.         if(notTrueMacBinary && bytes_to_read>size) bytes_to_read=size;
  2565.         if (readblock(&tarh, bytes_to_read))
  2566.              raise_error();
  2567.         if(bytes_to_read>size) bytes_to_read=size;    /* in true MacBinary, I may read
  2568.             from the archive more bytes than I write to the file */
  2569.         size -= bytes_to_read;
  2570.         if (!binp) macize_ASCII(tarh.name,bytes_to_read);
  2571.         
  2572.         if(write_hd((char*) &tarh, bytes_to_read)) pbsyserr(&pb);
  2573.     }
  2574.     if(flush_hd_buffer()) pbsyserr(&pb);
  2575.  
  2576.     get_openfile_location(pb.ioParam.ioRefNum);
  2577.  
  2578.     PBCloseSync(&pb);
  2579.     devo_chiudere_out=false;
  2580. }
  2581.  
  2582. void setmacbin ()
  2583. /* set the file informations from the MacBinary header */
  2584. {
  2585. FileParam fpb;
  2586. fpb.ioFVersNum = 0;
  2587. fpb.ioFDirIndex = 0;
  2588.  
  2589. if((fpb.ioDirID=openfile_dirID)!=0){
  2590.     fpb.ioVRefNum=openfile_vrefnum;
  2591.     fpb.ioNamePtr=mac_file_name;
  2592.     }
  2593. else{
  2594.     fpb.ioVRefNum=pb.fileParam.ioVRefNum;
  2595.     fpb.ioNamePtr=pb.fileParam.ioNamePtr;
  2596.     }
  2597.  
  2598. if (PBHGetFInfoSync(&fpb)) pbsyserr(&fpb);
  2599. clear_unused_fields();
  2600. mcopy(&fpb.ioFlFndrInfo, &macbinh.finfo, 10);
  2601. fpb.ioFlCrDat = macbinh.cdate;
  2602. fpb.ioFlMdDat = macbinh.mdate;
  2603.  
  2604. fpb.ioDirID=openfile_dirID;
  2605. if (PBHSetFInfoSync(&fpb)) pbsyserr(&fpb);
  2606. }
  2607.  
  2608. void untar_directory ()
  2609. {
  2610.   short len = strlen(tarh.name);
  2611.  
  2612.   if (len && tarh.name[len-1] != '/') {
  2613.     tarh.name[len] = '/';
  2614.     tarh.name[len+1] = '\0';
  2615.   }
  2616.   if(!bar_archive){
  2617.         if(sect_n<sectors_on_floppy)
  2618.             next_header_for_AIX=-1;
  2619.         else
  2620.             next_header_for_AIX=sect_n-sectors_on_floppy;
  2621.         }
  2622.   printf("Directory %s", tarh.name);
  2623.   if(fase==hack_listing && file_date!=-1) print_one_date(file_date+UNIXTIME,
  2624.       in_Italia?"  creata ":"  created ");
  2625.   printf("\n");
  2626.   unix_to_mac(tarh.name);
  2627.   if (!tarh.name[1] ) return;
  2628.   check_conf_dir(tarh.name);
  2629.   if(!listonly) create_directory(tarh.name);
  2630. }
  2631.  
  2632.  
  2633.  
  2634. /*  fname may contain a filename after the last ':', it will be ignored */
  2635. void create_directory (fname)
  2636.   char *fname;
  2637. {
  2638.   FileParam fpb;
  2639.   char name[128], *cp, *bp;
  2640.   OSErr i;
  2641.  
  2642.   cp = fname + strlen(fname);
  2643.   for (bp = fname; *bp == ':'; ++bp);
  2644.  
  2645.   fpb.ioNamePtr = (StringPtr) name;
  2646.   /* first loop: shorten the path until one directory is created: e.g. if
  2647.   d1 exists but d1/d2 does not, shorten d1/d2/d3/d4/filename to d1/d2
  2648.   because d1/d2/d3/d4 and d1/d2/d3 can't be created */
  2649.   do {
  2650.     while (cp[-1] != ':') --cp;
  2651.     if (cp == bp){ printf("%s - Bad directory name\n", fname); raise_error(); }
  2652.     strncpy(name+1, fname, name[0] = --cp - fname);
  2653.  
  2654.     retry:
  2655. #ifdef USA_CURRVREFN
  2656.     fpb.ioVRefNum = curr_vrefnum;
  2657. #else
  2658.     fpb.ioVRefNum = 0;
  2659. #endif
  2660.  
  2661.     fpb.ioDirID = 0;
  2662.     i=PBDirCreateSync(&fpb);
  2663.     if(i == dupFNErr){
  2664.         beep_in_foreground();
  2665.         if(fase==hack_reading){
  2666.             printf("Folder already existing\n");
  2667.             fpb.ioResult=noErr;
  2668.             return;
  2669.             }
  2670.         else{
  2671.             short item;
  2672.             do{
  2673.                 /*char buffer[128];
  2674.                 strcpy(buffer,tarh.name);
  2675.                 my_c2pstr(buffer);
  2676.                 while(buffer[0]>0 && buffer[buffer[0]]!=':')
  2677.                     buffer[0]--; */
  2678.                 item = my_semimodal_dialog(137,titoli_full,2,
  2679.                     in_Italia?"\pLa cartella\312":"\pThe folder\312",name,in_Italia?
  2680. "\p\resiste già: prima di cliccare su un bottone puoi\rvoler cambiar nome o spostare quella preesistente\ro puoi abortire il comando":
  2681. "\p\ralready exists: before clicking a button, you might\rwish to rename, move or delete the old one, or\ryou may abort the command");
  2682.                 if(item!=1){
  2683.                     select_directory();
  2684.                     if(reply.good)
  2685.                         goto retry;    /* se il folder esisteva non può che essere l'ultimo
  2686.                                 nel path altrimenti non l'avrebbe accorciato, quindi non
  2687.                                 c'è motivo di ripristinare il nome */
  2688.                     }
  2689.                 }
  2690.             while(item!=1);
  2691.             return;            /* It's useless to continue with the second loop: since
  2692.                             the path is not shortened when the prefix to the last
  2693.                             component name exists, I may be here only with the
  2694.                             original full path, so the second loop need not be executed,
  2695.                             and the date assignment must not
  2696.                             */
  2697.             }
  2698.         }
  2699.   } while ( i== dirNFErr || i==fnfErr);
  2700.  
  2701.   /* second loop: one by one, reinsert in the path all the directories after
  2702.   the one that was created in the first loop and create them: in the above
  2703.   example, create d1/d2/d3 and then d1/d2/d3/d4 */
  2704.   if (fpb.ioResult)pbsyserr(&fpb);
  2705.   while (1) {
  2706.     while (*++cp != ':')
  2707.         if (!*cp){
  2708.         /* new for suntar 1.3.2
  2709.         now, the last directory created is the originally requested directory:
  2710.         if the name was not followed by a file name, assign to it the creation date */
  2711.             CInfoPBRec cipb;
  2712.             if(file_date==-1 || fname[strlen(fname)-1]!=':' )
  2713.                  return;    /* the path contains a file name, hence the date
  2714.                      is of the file, not of the directory just created */
  2715.             fillmem(&cipb,0,sizeof(cipb));
  2716.             cipb.dirInfo.ioNamePtr= (StringPtr) name;
  2717.             cipb.dirInfo.ioVRefNum=curr_vrefnum;
  2718.             cipb.dirInfo.ioFDirIndex=0;
  2719.             if(i=PBGetCatInfoSync (&cipb)) return;
  2720.   
  2721.             cipb.dirInfo.ioNamePtr= (StringPtr) name;
  2722.             cipb.dirInfo.ioVRefNum=curr_vrefnum;
  2723.             cipb.dirInfo.ioDrDirID=0;
  2724.             cipb.dirInfo.ioDrMdDat=cipb.dirInfo.ioDrCrDat=
  2725.                 UNIXTIME+file_date;
  2726.               i=PBSetCatInfoSync (&cipb);
  2727.  
  2728.             return;
  2729.              }
  2730.     strncpy(name+1, fname, name[0] = cp - fname);
  2731.  
  2732. #ifdef USA_CURRVREFN
  2733.     fpb.ioVRefNum = curr_vrefnum;
  2734. #else
  2735.     fpb.ioVRefNum = 0;
  2736. #endif
  2737.  
  2738.     fpb.ioDirID = 0;
  2739.     if (PBDirCreateSync(&fpb)) pbsyserr(&fpb);
  2740.     }
  2741. }
  2742.  
  2743. short create_file (fname,perm,tempattrib)
  2744.   char *fname;
  2745.   short perm;
  2746.   Boolean tempattrib;
  2747. /* ritorna 1 se, causa nome doppio o bad name, il salvataggio è stato annullato
  2748. -- returns 1 if, due to a duplicate name, the user clicked on Cancel
  2749. */
  2750. {
  2751. /*
  2752. this routine was heavily modified by us (Speranza).
  2753. OK, it's incoherent that for duplicate names a dialog appears
  2754. while bad names are renamed without asking to the user...
  2755. */
  2756.     FileParam fpb;
  2757.     char name[128];
  2758.     extern SysEnvRec    gMac;
  2759.     Boolean opened_OK=false;
  2760.     Boolean changed;
  2761.  
  2762.     fillmem(&fpb,0,sizeof(fpb));
  2763.     fpb.ioNamePtr = my_c2pstr(strcpy(name, fname));
  2764.  
  2765.     while(!opened_OK){
  2766.  
  2767.     #ifdef USA_CURRVREFN
  2768.         fpb.ioVRefNum = curr_vrefnum;
  2769.     #else
  2770.         fpb.ioVRefNum = 0;
  2771.     #endif
  2772.  
  2773.         fpb.ioFVersNum = 0;
  2774.         if(!PBCreateSync(&fpb)) {
  2775.         #ifdef USA_CURRVREFN
  2776.             fpb.ioVRefNum = curr_vrefnum;
  2777.         #else
  2778.             fpb.ioVRefNum = 0;
  2779.         #endif
  2780.  
  2781.             fpb.ioFVersNum = 0;
  2782.             fpb.ioFDirIndex = 0;
  2783.             opened_OK=true;
  2784.             }
  2785.         else{
  2786. /*printf("creo %P con %d\n",name,fpb.ioResult);*/
  2787. /* The new network software from Apple has a bug: with System 7.0 and 7.01, 
  2788. when the "File Sharing Extension" is active (on our Mac LC which is not 
  2789. connected to a network), PBCreate returns paramErr (error in parameter block) 
  2790. when it should return bdNamErr (bad name) and fnfErr (file not found) when 
  2791. it should return dirNFErr (folder not found).
  2792.   Since fnfErr was not expected, we handle it as a dirNFErr. However, thinking
  2793. that any paramErr is a misnamed bdNamErr would be dangerous, hence we check that
  2794. the name contains a subname which is longer than 31 characters (since unix_to_mac
  2795. translates any non-ASCII char and checks the placing of ':', there should
  2796. be no other possible cause for a bad name) before translating the err code.
  2797. */
  2798.             if(fpb.ioResult==paramErr && too_long(fname) ) fpb.ioResult=bdNamErr;
  2799.  
  2800.             changed=false;
  2801.             if(fpb.ioResult == dupFNErr && is_bad_name(fname)){
  2802.                     fpb.ioResult=bdNamErr;    /* try again, by incrementing the number
  2803.                                         at start of the bad name... */
  2804.                     changed=true;        /* per non soddisfare il test che segue */
  2805.                     }
  2806.  
  2807.             if(fpb.ioResult == dupFNErr || fpb.ioResult==bdNamErr&&!changed&&is_bad_name(fname)){
  2808.                 if( gestisci_nome_doppio(fname,name,&fpb,fpb.ioResult == dupFNErr) )
  2809.                     return 1;    /* annullato...*/
  2810.                 opened_OK=true;
  2811.                 }
  2812.             else if(fpb.ioResult== bdNamErr){
  2813.                 /* check_foreground(); no, ma... non lo so */
  2814.                 SysBeep(5);
  2815.                 make_badname(fname,name);    /* o anche qui proporre di cambiare nome !*/
  2816.                 fpb.ioNamePtr = my_c2pstr(strcpy(name, fname));
  2817.                 }
  2818.             else if (fpb.ioResult == dirNFErr || fpb.ioResult==fnfErr){ /* System 7
  2819.                     sometimes returns fnfErr when the folder does not exist */
  2820.                     /* at least one directory specified in the path does not exist:
  2821.                     create it and retry */
  2822.                 create_directory(fname);
  2823.                 fpb.ioNamePtr = my_c2pstr(strcpy(name, fname));
  2824.                 }
  2825.             else{
  2826.                 pbsyserr(&fpb);
  2827.                 }
  2828.             }
  2829.           }
  2830.  
  2831.     fpb.ioNamePtr = my_c2pstr(strcpy(name, fname));
  2832.     if (PBGetFInfoSync(&fpb)) pbsyserr(&fpb);
  2833.     fpb.ioNamePtr = my_c2pstr(strcpy(name, fname));
  2834.     fpb.ioFlFndrInfo.fdType = filetype;
  2835.     fpb.ioFlFndrInfo.fdCreator = filecreator;
  2836.     if(file_aperto==ff_binhex)
  2837.         fpb.ioFlCrDat =macbinh.cdate;    /* non posso assegnare ora anche la data
  2838.             di modifica, perché sto per modificare il file: in macbinary e binhex
  2839.             lo faccio dopo, per il .info pazienza... Poi, è bene avere un'indicazione 
  2840.             che il salvataggio di un file non è stato completato (l'icona appare solo
  2841.             alla fine...)
  2842.             --there is no reason to set the modification date now, since I'm 
  2843.             going to modify the file ! That date is modified after closing the
  2844.             file, but not for the .info file. Also type and creator are set only
  2845.             when closing the file, so that the icon appears only when the file is 
  2846.             completed and may be opened by the application.
  2847.             */
  2848.     else if(file_date!=-1 )
  2849.         fpb.ioFlCrDat = file_date + UNIXTIME;
  2850.  
  2851.     if (PBSetFInfoSync(&fpb)) pbsyserr(&fpb);
  2852.  
  2853.     pStrcpy(mac_file_name,fpb.ioNamePtr);
  2854.     pb.ioParam.ioVRefNum = fpb.ioVRefNum;
  2855.     pb.ioParam.ioNamePtr = mac_file_name;
  2856.     pb.ioParam.ioVersNum = 0;
  2857.     pb.ioParam.ioPermssn = perm;
  2858.     pb.ioParam.ioMisc = 0;
  2859.     pb.ioParam.ioRefNum = 0;
  2860.     if (PBOpenSync(&pb)) pbsyserr(&pb);
  2861.     devo_chiudere_out=true;
  2862.     return 0;
  2863. }
  2864.  
  2865.  
  2866. void untar_link ()
  2867. {
  2868.   /*unix_to_mac(tarh.name);
  2869.   unix_to_mac(tarh.linkname);*/
  2870.   printf("Link %s -> %s%s\n",  tarh.name, tarh.linkname,
  2871.           listonly?"":in_Italia?" (ignorato)":" (ignored)");
  2872.   if(!bar_archive){
  2873.         if(sect_n<sectors_on_floppy)
  2874.             next_header_for_AIX=-1;
  2875.         else
  2876.             next_header_for_AIX=sect_n-sectors_on_floppy;
  2877.         }
  2878. }
  2879.  
  2880. /* Convert Unix pathname to a mac pathname.  Do not allow absolute
  2881.    names - "/foo/bar/baz" is treated as if it were "foo/bar/baz".
  2882. */
  2883. void unix_to_mac (name)
  2884.   char *name;
  2885. {
  2886.   char buf[102];
  2887.   register unsigned char *cp = name, *bp = buf, *op,c;
  2888.   *bp++ = ':';
  2889.   op = bp;
  2890.   while (1) {
  2891.     if (cp[0] == '/') ++cp;
  2892.     else if (cp[0] == '.' && cp[1] == '/') cp += 2;
  2893.     else if (cp[0] == '.' && cp[1] == '.' && cp[2] == '/') {
  2894.       if (op == bp) *bp++ = ':', op = bp;
  2895.       else for (--op; op != bp && op[-1] != ':'; --op);
  2896.       cp += 3;
  2897.     }
  2898.     else {
  2899.       while (c=*cp, c!=0 && c != '/'){
  2900.           if(c== ':')
  2901.               c= '/';
  2902.           else if(c=='_' && !pres_underscore)
  2903.               c=' ';
  2904.           else if(c<' '||c>126) c=0xC9;    /* '…' */
  2905.           *op++ = c;
  2906.           cp++;
  2907.           }
  2908.       if (!*cp++) break;
  2909.       *op++ = ':';
  2910.     }
  2911.   }
  2912.   *op = '\0';
  2913.   strcpy(name, buf);
  2914. }
  2915.  
  2916. #if 0
  2917. /* Name is the user-specified name, file is the actual tarred file */
  2918. void match_file (name, file)
  2919.   char *name, *file;
  2920. {
  2921.   char *cp;
  2922.   if (!strdiff(name, file)) return 1;
  2923.   if ((cp = strrchr(file, ':')) && !strdiff(cp+1, name)) return 1;
  2924.   if (name[strlen(name)-1] == ':' && strdiff(name, file) >= 0) return 1;
  2925.   return 0;
  2926. }
  2927.  
  2928. /* return 0 if the same, 1 if s1 is a substring of s2, -1 otherwise */
  2929. strdiff (s1, s2)
  2930.   char *s1, *s2;
  2931. {
  2932.   while (*s1) {
  2933.     if (*s1 != *s2) {
  2934.       char c1 = *s1;
  2935.       if ('A' <= c1 && c1 <= 'Z') c1 |= 0x20;
  2936.       if ('a' > c1 || c1 > 'z' || c1 != (*s2 | 0x20)) return -1;
  2937.     }
  2938.     ++s1, ++s2;
  2939.   }
  2940.   return (*s2 ? 1 : 0);
  2941. }
  2942. #endif
  2943.  
  2944. long untar_number (cp,doerror)
  2945.   char *cp;
  2946.   short doerror;
  2947. {
  2948.   short neg = 0;
  2949.   long num = 0;
  2950.   while (*cp == ' ') cp++;
  2951.   if (*cp == '-') neg++, cp++;
  2952.   if('0' <= *cp && *cp <= '7'){
  2953.       while ('0' <= *cp && *cp <= '7') num = (num<<3) + (*cp++ - '0');
  2954.       if (neg) num = -num;
  2955.       }
  2956.   else
  2957.       cp="A";        /* per fargli dare errore
  2958.                   -- in order to force the error */
  2959.   if(*cp!='\0'&&*cp!=' '){
  2960.       if(doerror>=0)
  2961.           printf(in_Italia?"Testata non in formato %car !\n":
  2962.               "Error: not a %car header !\n",bar_archive ? 'b' : 't');
  2963.       if(doerror>0)
  2964.           raise_error();
  2965.       else
  2966.           return -1L;
  2967.   }
  2968.   return num;
  2969. }
  2970.  
  2971. void pbsyserr (fpb)
  2972.   ioParam *fpb;
  2973. {
  2974.   short err = fpb->ioResult;
  2975.   char *name = (char*) fpb->ioNamePtr;
  2976.   my_p2cstr(name);
  2977.   start_of_line();
  2978.   if (err == fnfErr) printf("%s - File not found\n", name);
  2979.   else if (err == nsvErr) printf("%s - No such volume\n", name);
  2980.   else if (err == tmfoErr) printf("%s - Too many files open\n", name);
  2981.   else if (err == permErr) printf("%s - Permissions error\n", name);
  2982.   else if (err == dupFNErr) printf("%s - Duplicate filename\n", name);
  2983.   else if (err == eofErr) printf("%s - Premature end of file\n", name);
  2984.   else if (err == dskFulErr) printf("%s - Disk full\n", name);
  2985.   else if (err == opWrErr) printf("%s - Already open with write permission\n",name);
  2986.   else printf("%s - Error #%d\n", name, err);
  2987.   raise_error();
  2988. }
  2989.